예제 #1
0
		/// <summary>
		/// Converts a PHP value to the given CLR type that is a generic parameter.
		/// </summary>
		private static void EmitConvertToClrGeneric(ILEmitter/*!*/ il, Type/*!*/ formalType, LocalBuilder/*!*/ strictnessLocal)
		{
			Debug.Assert(formalType.IsGenericParameter);

			// f...ing GenericTypeParameterBuilder will not allow us to read its attributes and constraints :(
			if (!(formalType is GenericTypeParameterBuilder))
			{
				GenericParameterAttributes attrs = formalType.GenericParameterAttributes;
				if (Reflection.Enums.GenericParameterAttrTest(attrs, GenericParameterAttributes.NotNullableValueTypeConstraint))
				{
					// we know that we are converting to a value type
					il.Ldloca(strictnessLocal);
					il.Emit(OpCodes.Call, Methods.ConvertToClr.TryObjectToStruct.MakeGenericMethod(formalType));
					return;
				}

				Type[] constraints = formalType.GetGenericParameterConstraints();
				for (int i = 0; i < constraints.Length; i++)
				{
					if (constraints[i].IsClass)
					{
						if (!constraints[i].IsArray && !typeof(Delegate).IsAssignableFrom(constraints[i]))
						{
							// we know that we are converting to a class that is not an array nor a delegate
							il.Ldloca(strictnessLocal);
							il.Emit(OpCodes.Call, Methods.ConvertToClr.TryObjectToClass.MakeGenericMethod(formalType));
							return;
						}
						else break;
					}
				}
			}

			// postpone the conversion to runtime
			il.Ldloca(strictnessLocal);
			il.Emit(OpCodes.Call, Methods.Convert.TryObjectToType.MakeGenericMethod(formalType));
		}
예제 #2
0
		/// <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;
		}
예제 #3
0
파일: Places.cs 프로젝트: dw4dev/Phalanger
		/// <summary>
		/// Emits code that loads address of this storage place.
		/// </summary>
		/// <param name="il">The <see cref="ILEmitter"/> to emit the code to.</param>
		public void EmitLoadAddress(ILEmitter il)
		{
			switch (holder)
			{
				case PlaceHolder.Local: il.Ldloca(index); break;
				case PlaceHolder.Argument: il.Ldarga(index); break;
				case PlaceHolder.None: throw new InvalidOperationException();
			}
		}