/// <summary> /// Default ctor /// </summary> public XGenericInstanceType(XTypeReference elementType, IEnumerable<XTypeReference> genericArguments) : base(elementType) { this.genericArguments = genericArguments.ToList().AsReadOnly(); if (this.genericArguments.Count != GenericParameters.Count) throw new ArgumentException("Mismatch in generic parameter/argument count"); }
/// <summary> /// Create code to box the given source value into the given type. /// </summary> public static RLRange Box(this IRLBuilder builder, ISourceLocation sequencePoint, RegisterSpec source, XTypeReference type, DexTargetPackage targetPackage, IRegisterAllocator frame) { if (type.IsPrimitive) { if (type.IsByte()) builder.Add(sequencePoint, RCode.Int_to_byte, source.Register, source.Register); else if (type.IsUInt16()) builder.Add(sequencePoint, RCode.Int_to_short, source.Register, source.Register); // Call appropriate valueOf method var boxedType = type.Module.TypeSystem.Object; var r = frame.AllocateTemp(boxedType.GetReference(targetPackage)); var call = builder.Add(sequencePoint, RCode.Invoke_static, type.GetBoxValueOfMethod(), source.Registers); var last = builder.Add(sequencePoint, RCode.Move_result_object, r); return new RLRange(call, last, r); } if (type.IsGenericParameter) { var nop = builder.Add(sequencePoint, RCode.Nop); return new RLRange(nop, source); } XTypeDefinition typeDef ; if (type.TryResolve(out typeDef) && (typeDef.IsEnum)) { // Call appropriate valueOf method /*var boxedType = type.Module.TypeSystem.Object; var r = frame.AllocateTemp(boxedType.GetReference(target, nsConverter)); var call = builder.Add(sequencePoint, RCode.Invoke_static, typeDef.GetEnumUnderlyingType().GetBoxValueOfMethod(), source.Registers); var last = builder.Add(sequencePoint, RCode.Move_result_object, r); return new RLRange(call, last, r);*/ } // Just cast var checkCast = builder.Add(sequencePoint, RCode.Check_cast, type.GetReference(targetPackage), source); return new RLRange(checkCast, source); }
/// <summary> /// Default ctor /// </summary> protected XTypeSpecification(XTypeReference elementType) : base(elementType.Module, false, elementType.GenericParameters.Select(x => x.Name)) { if (elementType == null) throw new ArgumentNullException("elementType"); this.elementType = elementType; }
/// <summary> /// Is the given type an enum? /// </summary> public static bool IsEnum(this XTypeReference type) { type = type.GetWithoutModifiers(); XTypeDefinition typeDef; return(type.IsEnum(out typeDef)); }
private static void UnboxIfGeneric(XTypeReference type, AstExpression node, XTypeSystem typeSystem) { if (type.IsGenericParameter || type.IsGenericParameterArray()) { var resultType = node.GetResultType(); if (resultType.IsByReference && !type.IsByReference) { var elementType = resultType.ElementType; var clone = new AstExpression(node); node.SetCode(AstCode.SimpleCastclass).SetArguments(clone).Operand = elementType; } else { if (TreatAsStruct(type, resultType)) { ConvertUnboxStruct(node, resultType, typeSystem); } else { var clone = new AstExpression(node); node.SetCode(AstCode.UnboxFromGeneric).SetArguments(clone).Operand = type; } } } }
/// <summary> /// Is the given type a struct? /// </summary> public static bool IsStruct(this XTypeReference type) { XTypeDefinition typeDef; type = type.GetWithoutModifiers(); return(type.IsStruct(out typeDef)); }
/// <summary> /// Is the given type an array of a generic parameter? /// </summary> public static bool IsGenericParameterArray(this XTypeReference type) { if (!type.IsArray) { return(false); } return(type.ElementType.IsGenericParameter); }
/// <summary> /// Is the given type a reference to System.Collections.Generic.IEnumerable`1? /// </summary> public static bool IsSystemCollectionsIEnumerableT(this XTypeReference type) { if (type == null || !type.IsGenericInstance) { return(false); } return(type.GetWithoutModifiers().FullName == "System.Collections.Generic.IEnumerable`1"); }
/// <summary> /// Is the given type an array of a primitive elements? /// </summary> public static bool IsPrimitiveArray(this XTypeReference type) { if (!type.IsArray) { return(false); } return(type.ElementType.IsPrimitive); }
/// <summary> /// Is the given type a type definition or a normal type reference? /// </summary> public static bool IsDefinitionOrReferenceOrPrimitive(this XTypeReference type) { if (type.IsDefinition || type.IsPrimitive) { return(true); } return(type.Kind == XTypeReferenceKind.TypeReference); }
/// <summary> /// Is the given type a struct? /// </summary> public static bool IsStruct(this XTypeReference type, out XTypeDefinition typeDef) { typeDef = null; if (type == null) { return(false); } return(type.TryResolve(out typeDef) && typeDef.IsStruct); }
/// <summary> /// Is the given type of the given kind? /// </summary> public static bool Is(this XTypeReference type, XTypeReferenceKind kind1, XTypeReferenceKind kind2) { if (type == null) { return(false); } type = type.GetWithoutModifiers(); return((type.Kind == kind1) || (type.Kind == kind2)); }
/// <summary> /// Is the given type void? /// </summary> public static bool IsVoid(this XTypeReference type) { if (type == null) { return(false); } type = type.GetWithoutModifiers(); return((type.FullName == "System.Void") || type.Module.TypeSystem.Void.IsSame(type)); }
/// <summary> /// Default ctor /// </summary> public XGenericInstanceType(XTypeReference elementType, IEnumerable <XTypeReference> genericArguments) : base(elementType) { this.genericArguments = genericArguments.ToList().AsReadOnly(); if (this.genericArguments.Count != GenericParameters.Count) { throw new ArgumentException("Mismatch in generic parameter/argument count"); } }
/// <summary> /// Is the given type a type definition or a normal type reference? /// </summary> public static bool IsDefinitionOrReferenceOrPrimitive(this XTypeReference type) { type = type.GetWithoutModifiers(); if (type.IsDefinition || type.IsPrimitive) { return(true); } return(type.Kind == XTypeReferenceKind.TypeReference); }
/// <summary> /// Create a IGnericDefinition annotation and attaches it to the given provider. /// TODO: this might better belong somewhere else. /// </summary> public static void AddGenericDefinitionAnnotationIfGeneric(this IAnnotationProvider provider, XTypeReference xtype, AssemblyCompiler compiler, DexTargetPackage targetPackage, bool forceTypeDefinition=false) { if (!xtype.IsGenericInstance && !xtype.IsGenericParameter) return; Annotation annotation = GetGenericDefinitionAnnotationForType(xtype, forceTypeDefinition, compiler, targetPackage); if(annotation != null) provider.Annotations.Add(annotation); }
/// <summary> /// Default ctor /// </summary> protected XTypeSpecification(XTypeReference elementType) : base(elementType.Module, false, elementType.GenericParameters.Select(x => x.Name)) { if (elementType == null) { throw new ArgumentNullException("elementType"); } this.elementType = elementType; }
/// <summary> /// .NET ctor /// </summary> public DecompilerContext(XMethodDefinition currentMethod) { if (currentMethod == null) throw new ArgumentNullException("currentMethod"); name = currentMethod.Name; declaringTypeName = currentMethod.DeclaringType.Name; declaringType = currentMethod.DeclaringType; returnType = currentMethod.ReturnType; currentModule = currentMethod.Module; }
/// <summary> /// Is the given type a wide primitive (long, ulong, double)? /// </summary> public static bool IsWide(this XTypeReference type) { if (type == null) { return(false); } var ts = type.Module.TypeSystem; return(ts.Long.IsSame(type) || ts.ULong.IsSame(type) || ts.Double.IsSame(type)); }
/// <summary> /// Default ctor /// </summary> public Simple(string name, bool hasThis, XTypeReference returnType, XTypeReference declaringType, IEnumerable <XParameter> parameters, IEnumerable <string> genericParameterNames) : base(declaringType) { this.name = name; this.hasThis = hasThis; this.returnType = returnType; this.parameters = (parameters ?? Enumerable.Empty <XParameter>()).ToList().AsReadOnly(); genericParameters = (genericParameterNames ?? Enumerable.Empty <string>()).Select((x, i) => new XGenericParameter.SimpleXGenericParameter(this, i)).Cast <XGenericParameter>().ToList().AsReadOnly(); }
/// <summary> /// Is the given type an enum? /// </summary> public static bool IsEnum(this XTypeReference type, out XTypeDefinition typeDef) { typeDef = null; if (type == null) { return(false); } type = type.GetWithoutModifiers(); return(type.TryResolve(out typeDef) && typeDef.IsEnum); }
/// <summary> /// Convert the result of the given node to uint8/uint16 if needed. /// </summary> private static void Convert(AstExpression node, AstCode convertCode, XTypeReference expectedType) { // Copy load expression var clone = new AstExpression(node); // Convert node node.Code = convertCode; node.SetArguments(clone); node.Operand = null; node.SetType(expectedType); }
/// <summary> /// Does this type reference point to the same type as the given other reference? /// </summary> private bool IsSameX(XTypeReference other, bool ignoreSign) { var myKind = Kind; var otherKind = other.Kind; switch (myKind) { case XTypeReferenceKind.TypeReference: case XTypeReferenceKind.TypeDefinition: return(((otherKind == XTypeReferenceKind.TypeReference) || (otherKind == XTypeReferenceKind.TypeDefinition)) && (FullName == other.FullName)); case XTypeReferenceKind.GenericParameter: return((otherKind == XTypeReferenceKind.GenericParameter) && ((XGenericParameter)this).IsSame((XGenericParameter)other)); case XTypeReferenceKind.GenericInstanceType: return((otherKind == XTypeReferenceKind.GenericInstanceType) && ((XGenericInstanceType)this).IsSame((XGenericInstanceType)other)); case XTypeReferenceKind.ArrayType: case XTypeReferenceKind.ByReferenceType: case XTypeReferenceKind.PointerType: case XTypeReferenceKind.OptionalModifierType: case XTypeReferenceKind.RequiredModifierType: return((otherKind == myKind) && ElementType.IsSame(other.ElementType, ignoreSign)); case XTypeReferenceKind.Bool: case XTypeReferenceKind.Byte: case XTypeReferenceKind.SByte: case XTypeReferenceKind.Char: case XTypeReferenceKind.Short: case XTypeReferenceKind.UShort: case XTypeReferenceKind.Int: case XTypeReferenceKind.UInt: case XTypeReferenceKind.Long: case XTypeReferenceKind.ULong: case XTypeReferenceKind.Float: case XTypeReferenceKind.Double: case XTypeReferenceKind.Void: case XTypeReferenceKind.IntPtr: case XTypeReferenceKind.UIntPtr: if (ignoreSign) { otherKind = NormalizeSigned(otherKind); myKind = NormalizeSigned(myKind); } return(otherKind == myKind); default: throw new NotImplementedException(); } }
/// <summary> /// Is the given type a reference to System.Collections.Generic.ICollection`1? /// </summary> public static bool IsSystemCollectionsICollectionT(this XTypeReference type) { if (type == null) { return(false); } type = type.GetWithoutModifiers(); if (!type.IsGenericInstance) { return(false); } return(type.FullName == "System.Collections.Generic.ICollection`1"); }
/// <summary> /// Is the given type IEnumerable or a derived interface? /// </summary> public static bool ExtendsIEnumerable(this XTypeReference type) { if (type.FullName == "System.Collections.IEnumerable") { return(true); } XTypeDefinition typeDef; if (!type.TryResolve(out typeDef) || !typeDef.IsInterface) { return(false); } return(typeDef.Interfaces.Any(ExtendsIEnumerable)); }
/// <summary> /// get the ElementType stripped of Required- or OptionalModifierTypes /// (is this correct to do here?) /// </summary> /// <returns></returns> public virtual XTypeReference GetWithoutModifiers() { if (withoutModifiers != null) { return(withoutModifiers); } XTypeReference ret = this; while (ret is XRequiredModifierType || ret is XOptionalModifierType) { ret = ret.ElementType; } withoutModifiers = ret; return(ret); }
/// <summary> /// Is the given type System.Collections.ICollection or a derived interface? /// </summary> public static bool ExtendsICollection(this XTypeReference type) { type = type.GetWithoutModifiers(); if (type.FullName == "System.Collections.ICollection") { return(true); } XTypeDefinition typeDef; if (!type.TryResolve(out typeDef) || !typeDef.IsInterface) { return(false); } return(typeDef.Interfaces.Any(ExtendsICollection)); }
/// <summary> /// Is the given type System.Collections.IList, System.Collections.Generic.IList(T) or a derived interface? /// </summary> public static bool ExtendsIList(this XTypeReference type) { var fullName = type.FullName; if ((fullName == "System.Collections.IList") || (fullName == "System.Collections.Generic.IList`1")) { return(true); } XTypeDefinition typeDef; if (!type.TryResolve(out typeDef) || !typeDef.IsInterface) { return(false); } return(typeDef.Interfaces.Any(ExtendsIList)); }
/// <summary> /// Convert the result of the given node to uint8/uint16 if needed. /// </summary> private static void ConvertIfNeeded(AstExpression node, XTypeReference valueType, AstExpression parent) { AstCode convCode; if (valueType.IsByte()) { // Convert from int to uint8 convCode = AstCode.Int_to_ubyte; } else if (valueType.IsUInt16()) { // Convert from int to uint16 convCode = AstCode.Int_to_ushort; } else if (valueType.IsChar()) { // Convert from int to uint16 convCode = AstCode.Conv_U2; } else { // Do not convert return; } // Avoid recursion if ((parent != null) && (parent.Code == convCode)) return; // Copy load expression var clone = new AstExpression(node); // Convert node node.Code = convCode; node.Arguments.Clear(); node.Arguments.Add(clone); node.Operand = null; node.InferredType = valueType; // keep the expected type! node.ExpectedType = clone.ExpectedType; clone.ExpectedType = valueType; }
public static Annotation CreateAnnotation(XTypeReference xtype, bool forceTypeDefinition, AssemblyCompiler compiler, DexTargetPackage targetPackage) { var genericsDefAnnotationClass = compiler.GetDot42InternalType(InternalConstants.GenericDefinitionAnnotation) .GetClassReference(targetPackage); var annotation = new Annotation { Type = genericsDefAnnotationClass, Visibility = AnnotationVisibility.Runtime }; string s = GetDefinition(xtype, forceTypeDefinition, compiler, targetPackage); if (string.IsNullOrEmpty(s)) return null; annotation.Arguments.Add(new AnnotationArgument("Definition", s)); return annotation; }
/// <summary> /// Convert the given argument if it does not match the target type. /// </summary> private static void ConvertIfNeeded(AstExpression arg, XTypeReference targetType) { var argType = arg.GetResultType(); if (!targetType.IsSame(argType)) { if (targetType.IsChar()) { if (argType.IsUInt16() || argType.IsByte()) Convert(arg, AstCode.Conv_U2, targetType); } else if (targetType.IsUInt16()) { if (argType.IsChar() || argType.IsByte()) Convert(arg, AstCode.Int_to_ushort, targetType); } else if (targetType.IsInt16()) { if (argType.IsChar() || argType.IsByte()) Convert(arg, AstCode.Conv_I2, targetType); } } }
/// <summary> /// Is the given type a bool? /// </summary> public static bool IsBoolean(this XTypeReference type) { return((type != null) && type.Module.TypeSystem.Bool.IsSame(type)); }
/// <summary> /// Create code to unbox the given source array of boxed type elements resulting from a call into an array of primitive elements. /// </summary> public static RLRange UnboxGenericArrayResult(this IRLBuilder builder, ISourceLocation sequencePoint, RegisterSpec boxedArray, XTypeReference type, DexTargetPackage targetPackage, IRegisterAllocator frame, AssemblyCompiler compiler) { var internalBoxingType = compiler.GetDot42InternalType("Boxing").Resolve(); var primitiveArray = frame.AllocateTemp(type.GetReference(targetPackage)); var ilUnboxMethod = internalBoxingType.Methods.First(x => x.Name.StartsWith("Unbox") && (x.Parameters.Count == 1) && (x.ReturnType.IsSame(type, true))); var unboxMethod = ilUnboxMethod.GetReference(targetPackage); var call = builder.Add(sequencePoint, RCode.Invoke_static, unboxMethod, boxedArray); var saveArray = builder.Add(sequencePoint, RCode.Move_result_object, primitiveArray); return new RLRange(call, saveArray, primitiveArray); }
/// <summary> /// Create code to box the given source array of primitive type elements into an array of boxed elements. /// </summary> public static RLRange BoxGenericArray(this IRLBuilder builder, ISourceLocation sequencePoint, RegisterSpec source, XTypeReference type, DexTargetPackage targetPackage, IRegisterAllocator frame, AssemblyCompiler compiler) { var objectArrayType = new DexLib.ArrayType(new ClassReference("java.lang.Object")); var boxedArray = frame.AllocateTemp(objectArrayType); var internalBoxingType = compiler.GetDot42InternalType("Boxing").Resolve(); var ilBoxMethod = internalBoxingType.Methods.First(x => x.EqualsName("Box") && (x.Parameters.Count == 1) && (x.Parameters[0].ParameterType.IsSame(type, true))); var boxMethod = ilBoxMethod.GetReference(targetPackage); var call = builder.Add(sequencePoint, RCode.Invoke_static, boxMethod, source); var saveArray = builder.Add(sequencePoint, RCode.Move_result_object, boxedArray); return new RLRange(call, saveArray, boxedArray); }
/// <summary> /// Create code to unbox the given source value into the given type. /// </summary> public static RLRange Unbox(this IRLBuilder builder, ISourceLocation sequencePoint, RegisterSpec source, XTypeReference type, AssemblyCompiler compiler, DexTargetPackage targetPackage, IRegisterAllocator frame) { if (type.IsPrimitive) { RCode convertAfterCode; var rUnboxed = frame.AllocateTemp(type.GetReference(targetPackage)); var unboxValueMethod = type.GetUnboxValueMethod(compiler, targetPackage, out convertAfterCode); var first = builder.Add(sequencePoint, RCode.Invoke_static, unboxValueMethod, source); var last = builder.Add(sequencePoint, type.MoveResult(), rUnboxed); if (convertAfterCode != RCode.Nop) { last = builder.Add(sequencePoint, convertAfterCode, rUnboxed, rUnboxed); } return new RLRange(first, last, rUnboxed); } XTypeDefinition enumTypeDef; if (type.IsEnum(out enumTypeDef)) { var rUnboxed = frame.AllocateTemp(type.GetReference(targetPackage)); var unboxValueMethod = enumTypeDef.Methods.First(x => x.Name == NameConstants.Enum.UnboxMethodName).GetReference(targetPackage); var first = builder.Add(sequencePoint, RCode.Invoke_static, unboxValueMethod, source); var last = builder.Add(sequencePoint, type.MoveResult(), rUnboxed); return new RLRange(first, last, rUnboxed); } if (!type.IsGenericParameter) { // Just cast var checkCast = builder.Add(sequencePoint, RCode.Check_cast, type.GetReference(targetPackage), source); return new RLRange(checkCast, source); } // Do nothing var nop = builder.Add(sequencePoint, RCode.Nop); return new RLRange(nop, source); }
/// <summary> /// Gets a primitive type or null if the given type is not primitive. /// </summary> private static PrimitiveType GetPrimitiveType(XTypeReference type) { // Handle primitive types switch (type.Kind) { case XTypeReferenceKind.Bool: return PrimitiveType.Boolean; case XTypeReferenceKind.Char: return PrimitiveType.Char; case XTypeReferenceKind.Float: return PrimitiveType.Float; case XTypeReferenceKind.Double: return PrimitiveType.Double; case XTypeReferenceKind.SByte: case XTypeReferenceKind.Byte: return PrimitiveType.Byte; case XTypeReferenceKind.Short: case XTypeReferenceKind.UShort: return PrimitiveType.Short; case XTypeReferenceKind.Int: case XTypeReferenceKind.UInt: return PrimitiveType.Int; case XTypeReferenceKind.Long: case XTypeReferenceKind.ULong: return PrimitiveType.Long; case XTypeReferenceKind.Void: return PrimitiveType.Void; case XTypeReferenceKind.IntPtr: case XTypeReferenceKind.UIntPtr: return PrimitiveType.Int; // Is this correct? } return null; }
/// <summary> /// Default ctor /// </summary> protected XMemberReference(XModule module, XTypeReference declaringType) : base(module) { this.declaringType = declaringType; }
private static void ConvertUnboxStruct(AstExpression node, XTypeReference resultType, XTypeSystem typeSystem) { // Structs must never be null. We have to handle structs here, since a newobj // might need generic arguments. These would be difficult to provide at "UnboxFromGeneric", // but will be automatically filled in by the GenericInstanceConverter // convert to (temp$ = (T)x) != null ? temp$ : default(T) // replace any unbox, but keep if otherwise. var clone = node.Code == AstCode.Unbox ? new AstExpression(node.Arguments[0]) : new AstExpression(node); // make sure we don't evaluate the expression twice. var tempVar = new AstGeneratedVariable("temp$", "") { Type = typeSystem.Object }; // T(x) var txExpr = new AstExpression(node.SourceLocation, AstCode.SimpleCastclass, resultType, clone) .SetType(resultType); // temporary storage var storeTempVar = new AstExpression(node.SourceLocation, AstCode.Stloc, tempVar, txExpr) { ExpectedType = resultType }; var loadTempVar = new AstExpression(node.SourceLocation, AstCode.Ldloc, tempVar) .SetType(resultType); // default (T) var defaultT = new AstExpression(node.SourceLocation, AstCode.DefaultValue, resultType).SetType(resultType); var constructor = StructCallConverter.GetDefaultValueCtor(resultType.Resolve()); StructCallConverter.ConvertDefaultValue(defaultT, constructor); // Combine var conditional = new AstExpression(node.SourceLocation, AstCode.Conditional, resultType, storeTempVar, loadTempVar, defaultT) .SetType(resultType); node.CopyFrom(conditional); }
private static void BoxIfGeneric(XTypeReference type, AstExpression node) { // TODO: CLR allows return-by-reference, though C# does not. Do we need to handle this here? if (type.IsGenericParameter) { var resultType = node.GetResultType(); if (resultType.IsPrimitive) { var clone = new AstExpression(node); node.SetCode(AstCode.BoxToGeneric) .SetArguments(clone) .Operand = type; } } else if (type.IsGenericParameterArray()) { var resultType = node.GetResultType().ElementType; if (resultType.IsPrimitive) { var clone = new AstExpression(node); node.SetCode(AstCode.BoxToGeneric).SetArguments(clone).Operand = type; } } }
/// <summary> /// Is the given type a char? /// </summary> public static bool IsChar(this XTypeReference type) { return((type != null) && type.Module.TypeSystem.Char.IsSame(type)); }
/// <summary> /// Default ctor /// </summary> public SimpleXTypeReference(XModule module, string @namespace, string name, XTypeReference declaringType, bool isValueType, IEnumerable <string> genericParameterNames) : base(module, declaringType, isValueType, genericParameterNames) { ns = @namespace; this.name = name; }
/// <summary> /// Default ctor /// </summary> protected XTypeReferenceWithNamespace(XModule module, XTypeReference declaringType, bool isValueType, IEnumerable <string> genericParameterNames) : base(module, isValueType, genericParameterNames) { this.declaringType = declaringType; }
/// <summary> /// Is the given type System.Nullable<T>? /// </summary> public static bool IsNullableT(this XTypeReference type) { return(type.FullName == "System.Nullable`1"); }
private static string GetCollectionConvertMethodName(XTypeReference targetType) { if (targetType.IsSystemCollectionsIEnumerable()) return "Enumerable"; if (targetType.IsSystemCollectionsIEnumerableT()) return "EnumerableOfObject"; if (targetType.IsSystemCollectionsICollection()) return "Collection"; if (targetType.IsSystemCollectionsICollectionT()) return "CollectionOfObject"; if (targetType.IsSystemCollectionsIList()) return "List"; if (targetType.IsSystemCollectionsIListT()) return "ListOfObject"; return null; }
/// <summary> /// Generate an Add opcode. /// </summary> private static RCode OpcodeForType(XTypeReference type, RCode[] opcodes) { if (type.IsInt32() || type.IsUInt32() || type.IsInt16() || type.IsUInt16() || type.IsChar() || type.IsByte() || type.IsSByte() || type.IsBoolean()) return opcodes[0]; if (type.IsInt64() || type.IsUInt64()) return opcodes[1]; if (type.IsFloat()) return opcodes[2]; if (type.IsDouble()) return opcodes[3]; XTypeDefinition typeDef; if (type.TryResolve(out typeDef)) { if (typeDef.IsEnum) { return OpcodeForType(typeDef.GetEnumUnderlyingType(), opcodes); } } throw new ArgumentException("Unsupported type " + type); }
/// <summary> /// Create code to load a value from an annotation interface. /// </summary> /// <returns>The register(s) holding the value</returns> private static Register[] CreateLoadValueSequence( ISourceLocation seqp, MethodBody body, XTypeReference valueType, Register annotationReg, MethodDefinition getter, AssemblyCompiler compiler, DexTargetPackage targetPackage, out Instruction branchIfNotSet) { // NOTE: It would be better if we wouldn't get the values as object arrays // but as arrays of the actual type. // Apparently though the DexWriter will not write our attributes // if they contain arrays not of type object[]. Therefore the // conversion code below. // All in all it would be much cleaner if we could emit Ast code here // instead of RL code. List<Register> result = new List<Register>(); // get the array. Register regObject = body.AllocateRegister(RCategory.Temp, RType.Object); Register regIntVal = body.AllocateRegister(RCategory.Temp, RType.Value); body.Instructions.Add(seqp, RCode.Invoke_interface, getter, annotationReg); body.Instructions.Add(seqp, RCode.Move_result_object, regObject); // allocate result, initialize to default value. if (valueType.IsWide()) { Tuple<Register, Register> regs = body.AllocateWideRegister(RCategory.Temp); body.Instructions.Add(seqp, RCode.Const_wide, 0, regs.Item1); result.Add(regs.Item1); result.Add(regs.Item2); } else if (valueType.IsPrimitive) { Register reg = body.AllocateRegister(RCategory.Temp, RType.Value); body.Instructions.Add(seqp, RCode.Const, 0, reg); result.Add(reg); } else // object { Register reg = body.AllocateRegister(RCategory.Temp, RType.Object); body.Instructions.Add(seqp, RCode.Const, 0, reg); result.Add(reg); } // check if value is unset (array length 0) or null (array length 2) body.Instructions.Add(seqp, RCode.Array_length, regIntVal, regObject); branchIfNotSet = body.Instructions.Add(seqp, RCode.If_eqz, regIntVal); body.Instructions.Add(seqp, RCode.Rsub_int, 1, regIntVal, regIntVal); var branchOnNull = body.Instructions.Add(seqp, RCode.If_nez, regIntVal); // get the (boxed) value body.Instructions.Add(seqp, RCode.Const, 0, regIntVal); // convert to target type. if (valueType.IsArray) { Register regTmp = body.AllocateRegister(RCategory.Temp, RType.Object); Register regType = body.AllocateRegister(RCategory.Temp, RType.Object); var helper = compiler.GetDot42InternalType(InternalConstants.CompilerHelperName); var convertArray = helper.Resolve().Methods.First(p => p.Name == "ConvertArray" && p.Parameters.Count == 2) .GetReference(targetPackage); var underlying = valueType.ElementType.GetReference(targetPackage); body.Instructions.Add(seqp, RCode.Aget_object, regTmp, regObject, regIntVal); body.Instructions.Add(seqp, RCode.Const_class, underlying, regType); body.Instructions.Add(seqp, RCode.Invoke_static, convertArray, regTmp, regType); body.Instructions.Add(seqp, RCode.Move_result_object, result[0]); body.Instructions.Add(seqp, RCode.Check_cast, valueType.GetReference(targetPackage), result[0]); } else if (valueType.IsEnum()) { Register regTmp = body.AllocateRegister(RCategory.Temp, RType.Object); Register regType = body.AllocateRegister(RCategory.Temp, RType.Object); var getFromObject = compiler.GetDot42InternalType("Enum").Resolve() .Methods.Single(p=>p.Name == "GetFromObject") .GetReference(targetPackage); body.Instructions.Add(seqp, RCode.Aget_object, regTmp, regObject, regIntVal); body.Instructions.Add(seqp, RCode.Const_class, valueType.GetReference(targetPackage), regType); body.Instructions.Add(seqp, RCode.Invoke_static, getFromObject, regType, regTmp); body.Instructions.Add(seqp, valueType.MoveResult(), result[0]); body.Instructions.Add(seqp, RCode.Check_cast, valueType.GetReference(targetPackage), result[0]); } else if(!valueType.IsPrimitive) { body.Instructions.Add(seqp, RCode.Aget_object, result[0], regObject, regIntVal); body.Instructions.Add(seqp, RCode.Check_cast, valueType.GetReference(targetPackage), result[0]); } else { Register regTmp = body.AllocateRegister(RCategory.Temp, RType.Object); // unbox and store RCode afterConvert; var unbox = valueType.GetUnboxValueMethod(compiler, targetPackage, out afterConvert); body.Instructions.Add(seqp, RCode.Aget_object, regTmp, regObject, regIntVal); body.Instructions.Add(seqp, RCode.Invoke_static, unbox, regTmp); body.Instructions.Add(seqp, valueType.MoveResult(), result[0]); if (afterConvert != RCode.Nop) { body.Instructions.Add(seqp, afterConvert, result[0], result[0]); } } // nop will be removed at some stage later. var nop = body.Instructions.Add(seqp, RCode.Nop); branchOnNull.Operand = nop; return result.ToArray(); }
private static bool TreatAsStruct(XTypeReference type, XTypeReference resultType) { bool isStruct = resultType.IsStruct(); bool isNullable = false; if (isStruct) { var gp = type as XGenericParameter; if (gp != null) { var typeRef = gp.Owner as XTypeReference; if (typeRef != null) isNullable = typeRef.IsSystemNullable(); } } return isStruct && !isNullable; }
/// <summary> /// Is the given type a uint? /// </summary> public static bool IsUInt32(this XTypeReference type) { return((type != null) && type.Module.TypeSystem.UInt.IsSame(type)); }
public static Annotation GetGenericDefinitionAnnotationForType(XTypeReference xtype, bool forceTypeDefinition, AssemblyCompiler compiler, DexTargetPackage targetPackage) { var genericsDefAnnotationClass = compiler.GetDot42InternalType(InternalConstants.GenericDefinitionAnnotation) .GetClassReference(targetPackage); var annotation = new Annotation {Type = genericsDefAnnotationClass, Visibility = AnnotationVisibility.Runtime}; if (xtype.IsGenericInstance) { bool handled = false; List<object> genericArguments = new List<object>(); if (xtype.GetElementType().IsNullableT()) { // privitives and enums are represented by their marker classes. // no annotation needed. var argument = ((XGenericInstanceType) xtype).GenericArguments[0]; if (argument.IsEnum() || argument.IsPrimitive && !forceTypeDefinition) { return null; } // structs have marker classes. var classRef = xtype.GetReference(targetPackage) as ClassReference; var @class = classRef == null ? null : targetPackage.DexFile.GetClass(classRef.Fullname); if (@class != null && @class.NullableMarkerClass != null) { annotation.Arguments.Add(new AnnotationArgument("GenericInstanceType", @class.NullableMarkerClass)); handled = true; } } if (!handled) { foreach (var arg in ((XGenericInstanceType) xtype).GenericArguments) { if (arg.IsGenericParameter) { var gparm = (XGenericParameter) arg; // TODO: if we wanted to annotate methods as well, we should differentiate // between generic method arguments and generic type arguments. genericArguments.Add(gparm.Position); } else if (arg.IsGenericInstance) { var giparm = GetGenericDefinitionAnnotationForType((XGenericInstanceType) arg, true,compiler, targetPackage); genericArguments.Add(giparm); } else { genericArguments.Add(arg.GetReference(targetPackage)); } } annotation.Arguments.Add(new AnnotationArgument("GenericArguments", genericArguments.ToArray())); } } else // generic parameter { var parm = (XGenericParameter) xtype; annotation.Arguments.Add(new AnnotationArgument("GenericParameter", parm.Position)); } if(forceTypeDefinition && annotation.Arguments.All(a => a.Name != "GenericInstanceType")) annotation.Arguments.Add(new AnnotationArgument("GenericTypeDefinition", xtype.ElementType.GetReference(targetPackage))); return annotation; }
/// <summary> /// Gets a unbox method for the given primitive type. /// </summary> internal static MethodReference GetUnboxValueMethod(XTypeReference type, AssemblyCompiler compiler, DexTargetPackage targetPackage, out RCode convertAfterCode) { var info = Get(type); convertAfterCode = info.convertAfterCode; var boxingClass = compiler.GetDot42InternalType("Boxing").GetClassReference(targetPackage); return new MethodReference(boxingClass, info.unboxMethodName, new Prototype(info.primitiveType, new Parameter(FrameworkReferences.Object, "value"))); }
/// <summary> /// Gets the converted name of the given type. /// </summary> public static string GetConvertedName(XTypeReference type) { return ConvertTypeName(type.Name); }
/// <summary> /// Gets a unbox method for the given primitive type. /// </summary> internal static ClassReference GetBoxedType(XTypeReference type) { return Get(type).boxedClass; }
/// <summary> /// Returns the method name when converting an array to an IEnumerableT in compiler helper. /// /// (not sure if this is the best place for this method...) /// </summary> public static string GetAsEnumerableTMethodName(XTypeReference sourceArrayElementType) { var convertMethodName = "AsObjectEnumerable"; if (sourceArrayElementType.IsPrimitive) { if (sourceArrayElementType.IsBoolean()) convertMethodName = "AsBoolEnumerable"; else if (sourceArrayElementType.IsByte()) convertMethodName = "AsByteEnumerable"; else if (sourceArrayElementType.IsSByte()) convertMethodName = "AsSByteEnumerable"; else if (sourceArrayElementType.IsChar()) convertMethodName = "AsCharEnumerable"; else if (sourceArrayElementType.IsInt16()) convertMethodName = "AsInt16Enumerable"; else if (sourceArrayElementType.IsUInt16()) convertMethodName = "AsUInt16Enumerable"; else if (sourceArrayElementType.IsInt32()) convertMethodName = "AsInt32Enumerable"; else if (sourceArrayElementType.IsUInt32()) convertMethodName = "AsUInt32Enumerable"; else if (sourceArrayElementType.IsInt64()) convertMethodName = "AsInt64Enumerable"; else if (sourceArrayElementType.IsFloat()) convertMethodName = "AsFloatEnumerable"; else if (sourceArrayElementType.IsDouble()) convertMethodName = "AsDoubleEnumerable"; else throw new ArgumentOutOfRangeException("Unknown primitive array element type " + sourceArrayElementType); } return convertMethodName; }
/// <summary> /// Gets the box information for the given type. /// </summary> private static BoxInfo Get(XTypeReference type) { var info = Infos.FirstOrDefault(x => type.Is(x.metadataType)); if (info != null) return info; throw new ArgumentException(string.Format("No box information for for type {0}", type.FullName)); }
/// <summary> /// Emit code (if needed) to convert a value from source type to destination type. /// This method is used in "store" opcodes such stloc, stfld, stsfld, call /// </summary> internal static RLRange ConvertTypeBeforeStore(this IRLBuilder builder, ISourceLocation sequencePoint, XTypeReference sourceType, XTypeReference destinationType, RegisterSpec source, DexTargetPackage targetPackage, IRegisterAllocator frame, AssemblyCompiler compiler, out bool converted) { converted = false; if (sourceType.IsSame(destinationType)) { // Unsigned conversions if (sourceType.IsByte()) { var tmp = builder.EnsureTemp(sequencePoint, source, frame); var ins = builder.Add(sequencePoint, RCode.Int_to_byte, tmp.Result, tmp.Result); converted = true; return new RLRange(tmp, ins, tmp.Result); } else if (sourceType.IsUInt16()) { var tmp = builder.EnsureTemp(sequencePoint, source, frame); var ins = builder.Add(sequencePoint, RCode.Int_to_short, tmp.Result, tmp.Result); converted = true; return new RLRange(tmp, ins, tmp.Result); } return new RLRange(source); } if (sourceType.IsArray) { var compilerHelper = compiler.GetDot42InternalType(InternalConstants.CompilerHelperName).Resolve(); var arrayType = targetPackage.DexFile.GetClass(targetPackage.NameConverter.GetConvertedFullName(compilerHelper)); var sourceArrayElementType = ((XArrayType)sourceType).ElementType; if (destinationType.ExtendsIList()) { // Use ArrayHelper.AsList to convert var convertMethodName = "AsList"; var convertMethod = arrayType.GetMethod(convertMethodName); // Add code var tmp = builder.EnsureTemp(sequencePoint, source, frame); builder.Add(sequencePoint, RCode.Invoke_static, convertMethod, tmp.Result.Register); var last = builder.Add(sequencePoint, RCode.Move_result_object, tmp.Result.Register); converted = true; return new RLRange(tmp, last, tmp.Result); } if (destinationType.ExtendsICollection()) { // Use ArrayHelper.AsCollection to convert var convertMethodName = "AsCollection"; var convertMethod = arrayType.GetMethod(convertMethodName); // Add code var tmp = builder.EnsureTemp(sequencePoint, source, frame); builder.Add(sequencePoint, RCode.Invoke_static, convertMethod, tmp.Result.Register); var last = builder.Add(sequencePoint, RCode.Move_result_object, tmp.Result.Register); converted = true; return new RLRange(tmp, last, tmp.Result); } if (destinationType.ExtendsIEnumerable()) { // Use ArrayHelper.As...Enumerable to convert var convertMethodName = "AsObjectEnumerable"; if (sourceArrayElementType.IsPrimitive) { if (sourceArrayElementType.IsBoolean()) convertMethodName = "AsBoolEnumerable"; else if (sourceArrayElementType.IsByte()) convertMethodName = "AsByteEnumerable"; else if (sourceArrayElementType.IsSByte()) convertMethodName = "AsSByteEnumerable"; else if (sourceArrayElementType.IsChar()) convertMethodName = "AsCharEnumerable"; else if (sourceArrayElementType.IsInt16()) convertMethodName = "AsInt16Enumerable"; else if (sourceArrayElementType.IsUInt16()) convertMethodName = "AsUInt16Enumerable"; else if (sourceArrayElementType.IsInt32()) convertMethodName = "AsInt32Enumerable"; else if (sourceArrayElementType.IsUInt32()) convertMethodName = "AsUInt32Enumerable"; else if (sourceArrayElementType.IsInt64()) convertMethodName = "AsInt64Enumerable"; else if (sourceArrayElementType.IsFloat()) convertMethodName = "AsFloatEnumerable"; else if (sourceArrayElementType.IsDouble()) convertMethodName = "AsDoubleEnumerable"; else throw new ArgumentOutOfRangeException("Unknown primitive array element type " + sourceArrayElementType); } var convertMethod = arrayType.GetMethod(convertMethodName); // Add code var tmp = builder.EnsureTemp(sequencePoint, source, frame); builder.Add(sequencePoint, RCode.Invoke_static, convertMethod, tmp.Result.Register); var last = builder.Add(sequencePoint, RCode.Move_result_object, tmp.Result.Register); converted = true; return new RLRange(tmp, last, tmp.Result); } } // Do not convert return new RLRange(source); }
/// <summary> /// Gets a box method for the given primitive type. /// </summary> internal static MethodReference GetBoxValueOfMethod(XTypeReference type) { var info = Get(type); var cref = info.boxedClass; return new MethodReference(cref, "valueOf", new Prototype(cref, new Parameter(info.primitiveType, "value"))); }
/// <summary> /// Create code to unbox the given source array of boxed type elements into an array of primitive elements. /// </summary> public static RLRange UnboxGenericArray(this IRLBuilder builder, ISourceLocation sequencePoint, RegisterSpec source, RegisterSpec boxedArray, XTypeReference type, DexTargetPackage targetPackage, IRegisterAllocator frame, AssemblyCompiler compiler) { var internalBoxingType = compiler.GetDot42InternalType("Boxing").Resolve(); var ilUnboxMethod = internalBoxingType.Methods.First(x => x.EqualsName("UnboxTo") && (x.Parameters.Count == 2) && (x.Parameters[1].ParameterType.IsSame(type, true))); var unboxMethod = ilUnboxMethod.GetReference(targetPackage); var call = builder.Add(sequencePoint, RCode.Invoke_static, unboxMethod, boxedArray, source); return new RLRange(call, null); }
/// <summary> /// Convert ret or store field node. /// /// converts to IEnumerable, ICollection or IList if required. /// </summary> private static void ConvertRetOrStfldOrStsfld(AssemblyCompiler compiler, XTypeReference targetType, AstExpression node, XTypeSystem typeSystem) { var argument = node.Arguments.LastOrDefault(); if (argument == null) return; if (argument.InferredType == null || !argument.InferredType.IsArray) return; var methodName = GetCollectionConvertMethodName(targetType); if (methodName == null) return; // Call "ret asMethod(x)" var arrayHelper = compiler.GetDot42InternalType(InternalConstants.CompilerHelperName).Resolve(); var asArray = arrayHelper.Methods.First(x => x.Name == "As" + methodName); // AsX(x) var asXExpr = new AstExpression(node.SourceLocation, AstCode.Call, asArray, argument).SetType(typeSystem.Object); // replace argument. node.Arguments[node.Arguments.Count-1] = asXExpr; }
/// <summary> /// Does this type reference point to the same type as the given other reference? /// </summary> public virtual bool IsSame(XTypeReference other, bool ignoreSign = false) { return(ToCompareReference().IsSameX(other.ToCompareReference(), ignoreSign)); }
/// <summary> /// Is the given type a struct? /// </summary> public static bool IsStruct(this XTypeReference type) { XTypeDefinition typeDef; return(type.IsStruct(out typeDef)); }