/// <summary> /// Convert a nullable ctor into a convert function. /// </summary> private static void ConvertPrimitiveCtor(AstExpression node, XMethodReference ctor, XTypeReference type, AstExpression target, AstExpression value) { // Clear node node.Arguments.Clear(); node.InferredType = ctor.DeclaringType; node.ExpectedType = ctor.DeclaringType; switch (target.Code) { case AstCode.Ldloca: node.Code = AstCode.Stloc; node.Operand = target.Operand; node.Arguments.Add(new AstExpression(node.SourceLocation, AstCode.Box, type, value)); break; case AstCode.Ldflda: node.Code = AstCode.Stfld; node.Operand = target.Operand; node.Arguments.Add(new AstExpression(node.SourceLocation, AstCode.Box, type, value)); break; case AstCode.Ldsflda: node.Code = AstCode.Stsfld; node.Operand = target.Operand; node.Arguments.Add(new AstExpression(node.SourceLocation, AstCode.Box, type, value)); break; } }
/// <summary> /// Create the body of the Create(int|long) method. /// </summary> private AstBlock CreateCreateBody(XSyntheticMethodDefinition method, XMethodReference ctor) { return(AstBlock.CreateOptimizedForTarget( new AstExpression(AstNode.NoSource, AstCode.Ret, null, new AstExpression(AstNode.NoSource, AstCode.Newobj, ctor, new AstExpression(AstNode.NoSource, AstCode.Ldstr, "?"), new AstExpression(AstNode.NoSource, AstCode.Ldc_I4, -1), new AstExpression(AstNode.NoSource, AstCode.Ldloc, method.AstParameters[0]))))); }
/// <summary> /// Convert a nullable(PrimitiveT) ctor into a convert function. /// </summary> private static void ConvertPrimitiveNewObj(AstExpression node, XMethodReference ctor, XTypeReference type, AstExpression value) { // Clear node node.Arguments.Clear(); node.InferredType = ctor.DeclaringType; node.ExpectedType = ctor.DeclaringType; node.Code = AstCode.Box; node.Operand = type; node.Arguments.Add(value); }
/// <summary> /// Generate an Invoke opcode. /// </summary> internal static RCode Invoke(this XMethodDefinition targetMethod, XMethodReference targetMethodRef, MethodSource currentMethod, bool isSpecial = false) { if (targetMethod != null) { if (targetMethod.DeclaringType.IsDelegate()) { return(RCode.Invoke_interface); } if (targetMethod.IsStatic || targetMethod.IsAndroidExtension) { return(RCode.Invoke_static); } if ((currentMethod != null) && targetMethod.UseInvokeSuper(currentMethod.Method)) { return(RCode.Invoke_super); } if (isSpecial && !targetMethod.IsConstructor && (currentMethod != null) && targetMethod.DeclaringType.IsBaseOf(currentMethod.Method.DeclaringType)) { return(RCode.Invoke_super); } if (targetMethod.UseInvokeInterface) { return(RCode.Invoke_interface); } if (targetMethod.IsDirect) { return(RCode.Invoke_direct); } if (targetMethod.DeclaringType.IsInterface) { return(RCode.Invoke_interface); } } if (targetMethodRef != null) { if (!targetMethodRef.HasThis) { return(RCode.Invoke_static); } switch (targetMethodRef.Name) { case "<init>": case "<clinit>": case ".ctor": case ".cctor": return(RCode.Invoke_direct); } } return(RCode.Invoke_virtual); }
/// <summary> /// Convert a nullable .GetValueOrDefault() /// </summary> private static void ConvertPrimitiveGetValueOrDefault(AstExpression node, XMethodReference ilMethod, XTypeReference type, AstExpression target, XModule data) { // Clear node var originalArgs = node.Arguments.ToList(); var getValueRef = new XMethodReference.Simple("GetValue", false, ilMethod.ReturnType, ilMethod.DeclaringType, new[] { data.TypeSystem.Object, data.TypeSystem.Bool }, null); node.Operand = getValueRef; node.Arguments.Clear(); node.InferredType = type; node.ExpectedType = type; AddLoadArgument(node, target, originalArgs[0]); node.Arguments.Add(new AstExpression(node.SourceLocation, AstCode.Ldc_I4, 1) { InferredType = data.TypeSystem.Bool }); }
/// <summary> /// Gets the converted name of the given field. /// </summary> public static string GetConvertedName(XMethodReference method) { var name = method.Name; // Handle special names switch (name) { case ".ctor": return("<init>"); case ".cctor": return("<clinit>"); } // Handle properties in custom views. var methodDef = method.Resolve(); if (methodDef.DeclaringType.HasCustomViewAttribute()) { if (methodDef.IsSetter && name.StartsWith("set_")) { name = "set" + name.Substring(4); } else if (methodDef.IsGetter && name.StartsWith("get_")) { name = "get" + name.Substring(4); } } // Avoid special characters var originalName = name; name = name.Replace('<', '_'); name = name.Replace('>', '_'); name = name.Replace('.', '_'); if (name != originalName) { // Add hash to ensure unique name = name + '_' + GetHashPostfix(originalName); } return(name); }
/// <summary> /// Gets a Dex method reference for the given type reference. /// </summary> internal static MethodReference GetReference(this XMethodReference method, DexTargetPackage targetPackage) { if (method == null) { throw new ArgumentNullException("method"); } //#if DEBUG // if (method.DeclaringType.IsArray) // { // Debugger.Launch(); // } //#endif // Resolve the type to a method definition XMethodDefinition methodDef; if (method.TryResolve(out methodDef)) { string className; string memberName; string descriptor; if (methodDef.TryGetDexImportNames(out memberName, out descriptor, out className)) { var prototype = PrototypeBuilder.ParseMethodSignature(descriptor); return(new MethodReference(GetDeclaringTypeReference(className), memberName, prototype)); } // Method is in the assembly itself // Use the mapping return(targetPackage.NameConverter.GetMethod(methodDef)); } var javaMethod = method as XModel.Java.XBuilder.JavaMethodReference; if (javaMethod != null) { var prototype = PrototypeBuilder.ParseMethodSignature(javaMethod.JavaDecriptor); return(new MethodReference(GetDeclaringTypeReference(javaMethod.JavaClassName), javaMethod.JavaName, prototype)); } // Return reference to a method we do not know yet throw new ResolveException(string.Format("Method {0} not found", method.FullName)); }
public static void WriteTo(this XMethodReference method, ITextOutput writer) { if (method.HasThis) { writer.Write("instance "); } method.ReturnType.WriteTo(writer, AstNameSyntax.SignatureNoNamedTypeParameters); writer.Write(' '); if (method.DeclaringType != null) { method.DeclaringType.WriteTo(writer, AstNameSyntax.TypeName); writer.Write("::"); } writer.WriteReference(Escape(method.Name), method); var gim = method as XGenericInstanceMethod; if (gim != null) { writer.Write('<'); for (int i = 0; i < gim.GenericArguments.Count; i++) { if (i > 0) { writer.Write(", "); } gim.GenericArguments[i].WriteTo(writer); } writer.Write('>'); } writer.Write("("); var parameters = method.Parameters; for (int i = 0; i < parameters.Count; ++i) { if (i > 0) { writer.Write(", "); } parameters[i].ParameterType.WriteTo(writer, AstNameSyntax.SignatureNoNamedTypeParameters); } writer.Write(")"); }
/// <summary> /// The given call is a call to a ctor. /// Convert it to newobj /// </summary> private static void ConvertCtorCall(AstExpression callNode, XMethodReference ctor) { // Create a new node to construct the object var newObjNode = new AstExpression(callNode.SourceLocation, AstCode.Newobj, null, callNode.Arguments.Skip(1).ToList()); newObjNode.Operand = ctor; newObjNode.InferredType = ctor.DeclaringType; // Remove "this" argument var thisExpr = callNode.Arguments[0]; callNode.Arguments.Clear(); callNode.Arguments.Add(newObjNode); callNode.InferredType = ctor.DeclaringType; // Convert callNode to stX node switch (thisExpr.Code) { case AstCode.Ldloca: case AstCode.Ldloc: callNode.Code = AstCode.Stloc; callNode.Operand = thisExpr.Operand; break; case AstCode.Ldflda: case AstCode.Ldfld: callNode.Code = AstCode.Stfld; callNode.Operand = thisExpr.Operand; break; case AstCode.Ldsflda: case AstCode.Ldsfld: callNode.Code = AstCode.Stsfld; callNode.Operand = thisExpr.Operand; break; default: throw new NotSupportedException(string.Format("Unsupported opcode {0} in call to struct ctor", (int)thisExpr.Code)); } }
/// <summary> /// Is this reference equal to the given other reference? /// </summary> public override bool IsSameExceptDeclaringType(XMethodReference other) { if (base.IsSameExceptDeclaringType(other)) { return(true); } EnsureDexImportName(); // Check against dex import if ((dexImportName == other.Name) && (other.Parameters.Count == Parameters.Count) && (other.HasThis == HasThis)) { var descriptor = CreateNoGenericsDescriptor(this); var otherDescriptor = CreateNoGenericsDescriptor(other); return(descriptor == otherDescriptor); } EnsureJavaImportName(); // Check against java import if ((javaImportName == other.Name) && (other.Parameters.Count == Parameters.Count) && (other.HasThis == HasThis)) { var descriptor = CreateNoGenericsDescriptor(this); var otherDescriptor = CreateNoGenericsDescriptor(other); return(descriptor == otherDescriptor); } return(false); }
/// <summary> /// Create a descriptor for comparing the given method without generics. /// </summary> private static string CreateNoGenericsDescriptor(XMethodReference method) { return /*CreateNoGenericsDescriptor(method.ReturnType) + ":" +*/ (string.Join(",", method.Parameters.Select(x => XBuilder.CreateNoGenericsDescriptor(x.ParameterType)))); }
/// <summary> /// Create a descriptor for comparing the given method without generics. /// </summary> private static string CreateNoGenericsDescriptor(XMethodReference method) { return /*CreateNoGenericsDescriptor(method.ReturnType) + ":" +*/ string.Join(",", method.Parameters.Select(x => XBuilder.CreateNoGenericsDescriptor(x.ParameterType))); }
/// <summary> /// Is this reference equal to the given other reference? /// </summary> public override bool IsSameExceptDeclaringType(XMethodReference other) { if (base.IsSameExceptDeclaringType(other)) return true; EnsureDexImportName(); // Check against dex import if ((dexImportName == other.Name) && (other.Parameters.Count == Parameters.Count) && (other.HasThis == HasThis)) { var descriptor = CreateNoGenericsDescriptor(this); var otherDescriptor = CreateNoGenericsDescriptor(other); return (descriptor == otherDescriptor); } EnsureJavaImportName(); // Check against java import if ((javaImportName == other.Name) && (other.Parameters.Count == Parameters.Count) && (other.HasThis == HasThis)) { var descriptor = CreateNoGenericsDescriptor(this); var otherDescriptor = CreateNoGenericsDescriptor(other); return (descriptor == otherDescriptor); } return false; }
void ProcessArgument(AstExpression callNode, XMethodReference methodRef, int argumentIndex, MethodSource currentMethod, XModule assembly) { var node = callNode.Arguments[argumentIndex]; // Should we do something? switch (node.Code) { case AstCode.Ldloca: // Parameter case AstCode.AddressOf: // Local variable case AstCode.Ldflda: // Instance field case AstCode.Ldsflda: // Static field case AstCode.Ldelema: // Array break; case AstCode.Ldloc: if (!node.MatchThis() || !currentMethod.IsDotNet) { return; } break; default: return; } // Process argument var method = methodRef.Resolve(); var argIsThis = !method.IsStatic && (argumentIndex == 0); var parameterIndex = method.IsStatic ? argumentIndex : argumentIndex - 1; var parameter = argIsThis ? null : method.Parameters[parameterIndex]; var argType = argIsThis ? method.DeclaringType : parameter.ParameterType; //var argAttrs = argIsThis ? ParameterAttributes.None : parameter.Attributes; var argIsByRef = argType.IsByReference; var argIsOut = argIsThis ? false : argIsByRef && (parameter.Kind == XParameterKind.Output); // argIsByRef && argAttrs.HasFlag(ParameterAttributes.Out); var argIsGenByRefParam = argIsByRef && argType.ElementType.IsGenericParameter; switch (node.Code) { case AstCode.Ldloca: // Parameter { var variable = ((AstVariable)node.Operand); if (variable.Type.IsPrimitive || argIsByRef) { // Box first var ldloc = new AstExpression(node.SourceLocation, AstCode.Ldloc, node.Operand) { InferredType = variable.Type }; if (argIsByRef) { var stloc = new AstExpression(node.SourceLocation, AstCode.Stloc, node.Operand) { InferredType = variable.Type }; stloc.Arguments.Add(GetValueOutOfByRefArray(node, variable.Type, argIsGenByRefParam, assembly)); ConvertToByRefArray(node, variable.Type, ldloc, stloc, argIsOut, argIsGenByRefParam, argType.ElementType, assembly); } else { ConvertToBox(node, variable.Type, ldloc); } } else if (variable.Type.IsGenericParameter) { // Convert to ldarg var ldloc = new AstExpression(node.SourceLocation, AstCode.Ldloc, node.Operand) { InferredType = variable.Type }; callNode.Arguments[argumentIndex] = ldloc; } } break; case AstCode.Ldloc: // this { var variable = ((AstVariable)node.Operand); if (argIsThis && (variable.Type.IsByReference)) { node.SetType(variable.Type.ElementType); } else if (argIsByRef) { var ldclone = new AstExpression(node); var stExpr = new AstExpression(node.SourceLocation, AstCode.Nop, null); var elementType = variable.Type; if (elementType.IsByReference) { elementType = elementType.ElementType; } ConvertToByRefArray(node, elementType, ldclone, stExpr, argIsOut, argIsGenByRefParam, argType.ElementType, assembly); } } break; case AstCode.AddressOf: // Local variable { var arg = node.Arguments[0]; var type = arg.GetResultType(); var typeDef = type.Resolve(); if (typeDef.IsPrimitive) { if (argIsByRef) { throw new CompilerException("Unsupported use of AddressOf by byref argument"); } else { ConvertToBox(node, type, arg); } } } break; case AstCode.Ldflda: // Instance field case AstCode.Ldsflda: // Static field { var fieldRef = (XFieldReference)node.Operand; var field = fieldRef.Resolve(); if (field.FieldType.IsPrimitive || argIsByRef) { // Box first var ldfldCode = (node.Code == AstCode.Ldflda) ? AstCode.Ldfld : AstCode.Ldsfld; var ldfld = new AstExpression(node.SourceLocation, ldfldCode, node.Operand) { InferredType = field.FieldType }; ldfld.Arguments.AddRange(node.Arguments); if (argIsByRef) { var stfldCode = (node.Code == AstCode.Ldflda) ? AstCode.Stfld : AstCode.Stsfld; var stfld = new AstExpression(node.SourceLocation, stfldCode, node.Operand) { InferredType = field.FieldType }; stfld.Arguments.AddRange(node.Arguments); // instance stfld.Arguments.Add(GetValueOutOfByRefArray(node, field.FieldType, argIsGenByRefParam, assembly)); // value ConvertToByRefArray(node, field.FieldType, ldfld, stfld, argIsOut, argIsGenByRefParam, argType.ElementType, assembly); } else { ConvertToBox(node, field.FieldType, ldfld); } } } break; case AstCode.Ldelema: // Array element { var array = node.Arguments[0]; var arrayType = array.GetResultType(); var type = arrayType.ElementType; if (type.IsPrimitive || argIsByRef) { // Box first var ldElemCode = type.GetLdElemCode(); var ldelem = new AstExpression(node.SourceLocation, ldElemCode, node.Operand) { InferredType = type }; ldelem.Arguments.AddRange(node.Arguments); if (argIsByRef) { var stelemCode = type.GetStElemCode(); var stelem = new AstExpression(node.SourceLocation, stelemCode, node.Operand) { InferredType = type }; stelem.Arguments.AddRange(node.Arguments); stelem.Arguments.Add(GetValueOutOfByRefArray(node, type, argIsGenByRefParam, assembly)); ConvertToByRefArray(node, type, ldelem, stelem, argIsOut, argIsGenByRefParam, argType.ElementType, assembly); } else { ConvertToBox(node, type, ldelem); } } } break; } }
/// <summary> /// Create the body of the class ctor. /// </summary> private AstBlock CreateClassCtorBody(bool isWide, XFieldDefinition enumInfoField, XFieldDefinition defaultField, XMethodReference enumInfoCtor, XTypeReference valueType, XTypeSystem typeSystem) { var internalEnumType = Compiler.GetDot42InternalType("Enum"); var internalEnumInfoType = Compiler.GetDot42InternalType("EnumInfo"); var valueToFieldMap = new Dictionary <object, XFieldDefinition>(); var ldc = isWide ? AstCode.Ldc_I8 : AstCode.Ldc_I4; var ast = AstBlock.CreateOptimizedForTarget( // Instantiate enum info field new AstExpression(AstNode.NoSource, AstCode.Stsfld, enumInfoField, new AstExpression(AstNode.NoSource, AstCode.Newobj, enumInfoCtor))); // Instantiate values for each field var ordinal = 0; foreach (var field in XType.Fields.Where(x => x.IsStatic && !(x is XSyntheticFieldDefinition))) { // Find dex field object value; if (!field.TryGetEnumValue(out value)) { throw new CompilerException(string.Format("Cannot get enum value from field {0}", field.FullName)); } value = isWide ? (object)XConvert.ToLong(value) : (object)XConvert.ToInt(value); XFieldDefinition existingField; AstExpression valueExpr; if (valueToFieldMap.TryGetValue(value, out existingField)) { // Re-use instance of existing field valueExpr = new AstExpression(AstNode.NoSource, AstCode.Ldsfld, existingField); } else { // Record valueToFieldMap[value] = field; // Call ctor valueExpr = new AstExpression(AstNode.NoSource, AstCode.Newobj, ctor, new AstExpression(AstNode.NoSource, AstCode.Ldstr, field.Name), new AstExpression(AstNode.NoSource, AstCode.Ldc_I4, ordinal), new AstExpression(AstNode.NoSource, ldc, value)); } // Initialize static field ast.Body.Add(new AstExpression(AstNode.NoSource, AstCode.Stsfld, field, valueExpr)); // Add to info var addMethod = new XMethodReference.Simple("Add", true, typeSystem.Void, internalEnumInfoType, XParameter.Create("value", valueType), XParameter.Create("instance", internalEnumType)); ast.Body.Add(new AstExpression(AstNode.NoSource, AstCode.Call, addMethod, new AstExpression(AstNode.NoSource, AstCode.Ldsfld, enumInfoField), new AstExpression(AstNode.NoSource, ldc, value), new AstExpression(AstNode.NoSource, AstCode.Ldsfld, field))); // Increment ordinal ordinal++; } // Initialize default field var getValueMethod = new XMethodReference.Simple("GetValue", true, internalEnumType, internalEnumInfoType, XParameter.Create("value", valueType)); ast.Body.Add(new AstExpression(AstNode.NoSource, AstCode.Stsfld, defaultField, new AstExpression(AstNode.NoSource, AstCode.SimpleCastclass, XType, new AstExpression(AstNode.NoSource, AstCode.Call, getValueMethod, new AstExpression(AstNode.NoSource, AstCode.Ldsfld, enumInfoField), new AstExpression(AstNode.NoSource, ldc, 0))))); // Return ast.Body.Add(new AstExpression(AstNode.NoSource, AstCode.Ret, null)); return(ast); }