internal static void EmitConstrainedCoercion(ILEmitter/*!*/ il, Type/*!*/ narrow, Type/*!*/ wide, object threshold)
		{
			Label else_label = il.DefineLabel();
			Label endif_label = il.DefineLabel();

			il.Emit(OpCodes.Dup);

			// IF (STACK <= threshold) THEN
			il.LoadLiteral(threshold);
			il.Emit(OpCodes.Bgt_S, else_label);

			// LOAD (narrow)STACK
			il.Conv(narrow, false);
			il.Emit(OpCodes.Box, narrow);

			il.Emit(OpCodes.Br_S, endif_label);

			// ELSE
			il.MarkLabel(else_label);

			// LOAD (wide)STACK

			il.Conv(wide, false);
			il.Emit(OpCodes.Box, wide);

			// ENDIF
			il.MarkLabel(endif_label);
		}
		/// <summary>
		/// Converts object to CLR type
		/// </summary>
		private static bool EmitConvertObjectToClr(ILEmitter il, PhpTypeCode typeCode, Type formalType, LocalBuilder strictnessLocal)
		{
			MethodInfo convert_method = null;
			switch (Type.GetTypeCode(formalType))
			{
				case TypeCode.Boolean: if (typeCode != PhpTypeCode.Boolean)
						convert_method = Methods.ConvertToClr.TryObjectToBoolean; break;
				case TypeCode.Int32: if (typeCode != PhpTypeCode.Integer)
						convert_method = Methods.ConvertToClr.TryObjectToInt32; break;
				case TypeCode.Int64: if (typeCode != PhpTypeCode.LongInteger)
						convert_method = Methods.ConvertToClr.TryObjectToInt64; break;
				case TypeCode.Double: if (typeCode != PhpTypeCode.Double)
						convert_method = Methods.ConvertToClr.TryObjectToDouble; break;
				case TypeCode.String: if (typeCode != PhpTypeCode.String)
						convert_method = Methods.ConvertToClr.TryObjectToString; break;

				case TypeCode.SByte: convert_method = Methods.ConvertToClr.TryObjectToInt8; break;
				case TypeCode.Int16: convert_method = Methods.ConvertToClr.TryObjectToInt16; break;
				case TypeCode.Byte: convert_method = Methods.ConvertToClr.TryObjectToUInt8; break;
				case TypeCode.UInt16: convert_method = Methods.ConvertToClr.TryObjectToUInt16; break;
				case TypeCode.UInt32: convert_method = Methods.ConvertToClr.TryObjectToUInt32; break;
				case TypeCode.UInt64: convert_method = Methods.ConvertToClr.TryObjectToUInt64; break;
				case TypeCode.Single: convert_method = Methods.ConvertToClr.TryObjectToSingle; break;
				case TypeCode.Decimal: convert_method = Methods.ConvertToClr.TryObjectToDecimal; break;
				case TypeCode.Char: convert_method = Methods.ConvertToClr.TryObjectToChar; break;
				case TypeCode.DateTime: convert_method = Methods.ConvertToClr.TryObjectToDateTime; break;
				case TypeCode.DBNull: convert_method = Methods.ConvertToClr.TryObjectToDBNull; break;

				case TypeCode.Object:
					{
						if (formalType.IsValueType)
						{
							if (formalType.IsGenericType && NullableType == formalType.GetGenericTypeDefinition())
							{
								// This is an ugly corner case (using generic TryObjectToStruct wouldn't work, because
								// for nullables .IsValueType returns true, but it doesn't match "T : struct" constraint)!
								// We have to try converting object to Nullable<T> first and then to T
								// (which requires a new call to 'EmitConvertObjectToClr') 
								Type nullableArg = formalType.GetGenericArguments()[0];
								Type nullableType = NullableType.MakeGenericType(nullableArg);
								
								LocalBuilder tmpVar = il.DeclareLocal(typeof(object));
								
								// This succeeds only for exact match
								il.Emit(OpCodes.Call, Methods.ConvertToClr.UnwrapNullable);
								il.Emit(OpCodes.Dup);
								il.Stloc(tmpVar);

								// <stack_0> = tmpVar = UnwrapNullable(...)
								// if (<stack_0> != null) 
								Label lblNull = il.DefineLabel(), lblDone = il.DefineLabel();
								il.Emit(OpCodes.Ldnull);
								il.Emit(OpCodes.Beq, lblNull);
								// {

								// Convert tmpVar to T and wrap it into Nullable<T>
								il.Ldloc(tmpVar);
								bool ret = EmitConvertObjectToClr(il, typeCode, nullableArg, strictnessLocal);
								// TODO: use reflection cache?
								il.Emit(OpCodes.Newobj, nullableType.GetConstructors()[0]);
								il.Emit(OpCodes.Br, lblDone);
								
								// } else /* == null */ {
								il.MarkLabel(lblNull);

								// return (T?)null;
								LocalBuilder tmpNull = il.DeclareLocal(nullableType);
								il.Ldloca(tmpNull);
								il.Emit(OpCodes.Initobj, nullableType);
								il.Ldloc(tmpNull);
								// }
								
								il.MarkLabel(lblDone);
								return ret;
							}
							else
								convert_method = Methods.ConvertToClr.TryObjectToStruct.MakeGenericMethod(formalType);
						}
						else
						{
							if (formalType.IsArray)
								convert_method = Methods.ConvertToClr.TryObjectToArray.MakeGenericMethod(formalType.GetElementType());
							else if (typeof(Delegate).IsAssignableFrom(formalType))
								convert_method = Methods.ConvertToClr.TryObjectToDelegate.MakeGenericMethod(formalType);
							else
								convert_method = Methods.ConvertToClr.TryObjectToClass.MakeGenericMethod(formalType);
						}
						break;
					}

				default:
					Debug.Fail();
					return true;
			}

			if (convert_method != null)
			{
				il.Ldloca(strictnessLocal);
				il.Emit(OpCodes.Call, convert_method);
				return false;
			}
			else return true;
		}
Exemple #3
0
		internal void EmitSetConversion(ILEmitter/*!*/ il, PhpTypeCode sourceTypeCode, Type/*!*/ targetType)
		{
			LocalBuilder strictness = il.GetTemporaryLocal(typeof(PHP.Core.ConvertToClr.ConversionStrictness));
			if (!ClrOverloadBuilder.EmitConvertToClr(il, sourceTypeCode, targetType, strictness))
			{
				Label label_ok = il.DefineLabel();

				il.Ldloc(strictness);
				il.LdcI4((int)PHP.Core.ConvertToClr.ConversionStrictness.Failed);
				il.Emit(OpCodes.Ceq);
				il.Emit(OpCodes.Brfalse, label_ok);

				il.Emit(OpCodes.Ldstr, Property.DeclaringType.FullName);
				il.Emit(OpCodes.Ldstr, Property.FullName);
				il.Emit(OpCodes.Call, Methods.PhpException.PropertyTypeMismatch);

				il.MarkLabel(label_ok, true);
			}
			il.ReturnTemporaryLocal(strictness);
		}
Exemple #4
0
		/// <summary>
		/// Emits call to <see cref="ScriptContext.DeclareFunction"/>.
		/// </summary>
		internal static void EmitDeclareFunction(ILEmitter/*!*/il, IPlace/*!*/scriptContextPlace, PhpFunction/*!*/ function)
        {
            Label lbl_fieldinitialized = il.DefineLabel();

            // private static PhpRoutine <routine>'function = null;
            var attrs = FieldAttributes.Static | FieldAttributes.Private;
            var field = il.TypeBuilder.DefineField(string.Format("<routine>'{0}", function.FullName), typeof(PhpRoutineDesc), attrs);

            // if (<field> == null)
            il.Emit(OpCodes.Ldsfld, field);
            il.Emit(OpCodes.Brtrue, lbl_fieldinitialized);
            {
                // <field> = new PhpRoutineDesc(<attributes>, new RoutineDelegate(null, <delegate>))

                // LOAD <attributes>;
                il.LdcI4((int)function.MemberDesc.MemberAttributes);

                // new RoutineDelegate(null, <delegate>, true)
                il.Emit(OpCodes.Ldnull);
                il.Emit(OpCodes.Ldftn, function.ArgLessInfo);
                il.Emit(OpCodes.Newobj, Constructors.RoutineDelegate);
                il.LoadBool(true);

                // new PhpRoutineDesc:
                il.Emit(OpCodes.Newobj, Constructors.PhpRoutineDesc_Attr_Delegate_Bool);

                // <field> = <STACK>
                il.Emit(OpCodes.Stsfld, field);

                // new PurePhpFunction(<field>, fullName, argfull);   // writes desc.Member
                il.Emit(OpCodes.Ldsfld, field);
                il.Emit(OpCodes.Ldstr, function.FullName);
                CodeGenerator.EmitLoadMethodInfo(il, function.ArgFullInfo/*, AssemblyBuilder.DelegateBuilder*/);
                il.Emit(OpCodes.Newobj, Constructors.PurePhpFunction);
                il.Emit(OpCodes.Pop);
                
            }
            il.MarkLabel(lbl_fieldinitialized);

            // CALL ScriptContent.DeclareFunction(<field>, <name>);
            scriptContextPlace.EmitLoad(il);
            
            // LOAD <field>
            il.Emit(OpCodes.Ldsfld, field);            

            // LOAD <fullName>
            il.Emit(OpCodes.Ldstr, function.FullName);

            //
            il.Emit(OpCodes.Call, Methods.ScriptContext.DeclareFunction);
        }
Exemple #5
0
        /// <summary>
        /// Define new instance of CallSite&lt;<paramref name="delegateType"/>&gt; and initialize it with specified binder.
        /// </summary>
        /// <param name="bodyEmitter"><see cref="ILEmitter"/> of the body that is using this call site. This method may emit initialization of the call site into this <paramref name="bodyEmitter"/>.</param>
        /// <param name="userFriendlyName">User friendly name used as name for the CallSite field.</param>
        /// <param name="delegateType">CallSite type argument.</param>
        /// <param name="binderInstanceEmitter">Function used to emit initialization of the binder from within the call sites container .cctor.</param>
        /// <returns>The <see cref="FieldInfo"/> containing the instance of the created CallSite.</returns>
        public FieldInfo/*!*/DefineCallSite(ILEmitter/*!*/bodyEmitter,string/*!*/userFriendlyName, Type/*!*/delegateType, Action<ILEmitter>/*!*/binderInstanceEmitter)
        {
            Debug.Assert(userFriendlyName != null && delegateType != null && binderInstanceEmitter != null);

            userFriendlyName += ("'" + (callSitesCount++));

            // call sites container 
            var type = EnsureContainer();

            // call site type
            var callSiteType = Types.CallSiteGeneric[0].MakeGenericType(delegateType);

            // define the field:
            // public static readonly CallSite<delegateType> <userFriendlyName>
            var attrs = FieldAttributes.Static | FieldAttributes.InitOnly | ((staticCtorEmitter == null) ? FieldAttributes.Private : FieldAttributes.Public);
            var field = type.DefineField(PluginHandler.ConvertCallSiteName(userFriendlyName), callSiteType, attrs);

            if (staticCtorEmitter == null) // => this.classContext != null
            {
                // emit initialization of the call site just in the body of current method (as it is in C#, we need current generic arguments):
                Debug.Assert(this.classContext != null);
                
                // check if the call site if not null, otherwise initialize it first:

                // if (<field> == null) <InitializeCallSite>;
                Label ifend = bodyEmitter.DefineLabel();
                bodyEmitter.Emit(OpCodes.Ldsfld, field);
                bodyEmitter.Emit(OpCodes.Brtrue, ifend);

                // init the field:
                InitializeCallSite(bodyEmitter, callSiteType, field, binderInstanceEmitter);

                bodyEmitter.MarkLabel(ifend);
            }
            else
            {
                // init the field in .cctor:
                InitializeCallSite(staticCtorEmitter, callSiteType, field, binderInstanceEmitter);
            }

            //
            return field;
        }
Exemple #6
0
		internal void EmitDefinition(CodeGenerator/*!*/ codeGenerator)
		{
            if (type.IsComplete)
            {
                Debug.Assert(type.IsComplete, "Incomplete types should be converted to evals.");
                Debug.Assert(type.RealTypeBuilder != null, "A class declared during compilation should have a type builder.");

                attributes.Emit(codeGenerator, this);
                typeSignature.Emit(codeGenerator);

                codeGenerator.EnterTypeDeclaration(type);

                foreach (TypeMemberDecl member_decl in members)
                {
                    member_decl.EnterCodegenerator(codeGenerator);
                    member_decl.Emit(codeGenerator);
                    member_decl.LeaveCodegenerator(codeGenerator);
                }

                // emit stubs for implemented methods & properties that were not declared by this type:
                codeGenerator.EmitGhostStubs(type);

                codeGenerator.LeaveTypeDeclaration();
            }
            else
            {
                Debug.Assert(this.typeDefinitionCode != null);

                // LOAD DynamicCode.Eval(<code>, context, definedVariables, self, includer, source, line, column, evalId)
                
                // wrap Eval into static method
                MethodBuilder method = codeGenerator.IL.TypeBuilder.DefineMethod(
                    string.Format("{0}{1}", ScriptModule.DeclareHelperNane, type.FullName),
                    MethodAttributes.Private | MethodAttributes.Static | MethodAttributes.SpecialName,
                    Types.Void, Types.ScriptContext);

                var il = new ILEmitter(method);
                    
                codeGenerator.EnterLambdaDeclaration(il, false, LiteralPlace.Null, new IndexedPlace(PlaceHolder.Argument, 0), LiteralPlace.Null, LiteralPlace.Null);
                if (true)
                {
                    codeGenerator.EmitEval(
                        EvalKinds.SyntheticEval,
                        new StringLiteral(position, this.typeDefinitionCode, AccessType.Read),
                        position,
                        (this.Namespace != null) ? this.Namespace.QualifiedName : (QualifiedName?)null, this.validAliases);
                    il.Emit(OpCodes.Pop);
                    il.Emit(OpCodes.Ret);
                }
                codeGenerator.LeaveFunctionDeclaration();

                //
                il = codeGenerator.IL;

                type.IncompleteClassDeclareMethodInfo = method;
                type.IncompleteClassDeclarationId = String.Format("{0}${1}:{2}:{3}", type.FullName, unchecked((uint)codeGenerator.SourceUnit.SourceFile.ToString().GetHashCode()), position.FirstLine, position.FirstColumn);

                // sequence point here
                codeGenerator.MarkSequencePoint(position.FirstLine, position.FirstColumn, position.LastLine, position.LastColumn + 2);
                
                if (type.Declaration.IsConditional)
                {
                    // CALL <Declare>.<FullName>(<context>)
                    codeGenerator.EmitLoadScriptContext();
                    il.Emit(OpCodes.Call, method);
                }
                else
                {
                    // if (!<context>.IncompleteTypeDeclared(<id>))
                    //     CALL <Declare>.<FullName>(<context>)
                    var end_if = il.DefineLabel();

                    codeGenerator.EmitLoadScriptContext();
                    il.Emit(OpCodes.Ldstr, type.IncompleteClassDeclarationId);
                    il.Emit(OpCodes.Call, Methods.ScriptContext.IncompleteTypeDeclared);
                    il.Emit(OpCodes.Brtrue, end_if);
                    if (true)
                    {
                        codeGenerator.EmitLoadScriptContext();
                        il.Emit(OpCodes.Call, type.IncompleteClassDeclareMethodInfo);
                    }
                    il.MarkLabel(end_if);
                    il.ForgetLabel(end_if);
                }
            }
		}