public static XTypeReference SubstituteTypeArgs(XTypeReference type, XMemberReference member) { if (type is XTypeSpecification) { var arrayType = type as XArrayType; if (arrayType != null) { var elementType = SubstituteTypeArgs(arrayType.ElementType, member); if (elementType != arrayType.ElementType) { var newArrayType = new XArrayType(elementType, arrayType.Dimensions); return newArrayType; } else { return type; } } var refType = type as XByReferenceType; if (refType != null) { var elementType = SubstituteTypeArgs(refType.ElementType, member); return elementType != refType.ElementType ? new XByReferenceType(elementType) : type; } var giType = type as XGenericInstanceType; if (giType != null) { var genericArgs = giType.GenericArguments.ToArray(); var isChanged = false; for (int i = 0; i < giType.GenericArguments.Count; i++) { var argType = SubstituteTypeArgs(giType.GenericArguments[i], member); if (genericArgs[i] != argType) { isChanged = true; genericArgs[i] = argType; } } return isChanged ? new XGenericInstanceType(giType.ElementType, genericArgs) : type; } var optmodType = type as XOptionalModifierType; if (optmodType != null) { var elementType = SubstituteTypeArgs(optmodType.ElementType, member); return elementType != optmodType.ElementType ? new XOptionalModifierType(optmodType.ModifierType, elementType) : type; } var reqmodType = type as XRequiredModifierType; if (reqmodType != null) { var elementType = SubstituteTypeArgs(reqmodType.ElementType, member); return elementType != reqmodType.ElementType ? new XRequiredModifierType(reqmodType.ModifierType, elementType) : type; } var ptrType = type as XPointerType; if (ptrType != null) { var elementType = SubstituteTypeArgs(ptrType.ElementType, member); return elementType != ptrType.ElementType ? new XPointerType(elementType) : type; } } var gp = type as XGenericParameter; if (gp != null) { var declaringType = member.DeclaringType; if (declaringType is XArrayType) { return ((XArrayType)declaringType).ElementType; } if (gp.Owner is XMethodReference) { var giMethod = member as XGenericInstanceMethod; if (giMethod != null) return giMethod.GenericArguments[gp.Position]; } else if (declaringType.IsGenericInstance) { return ((XGenericInstanceType)declaringType).GenericArguments[gp.Position]; } } return type; }
/// <summary> /// Optimize expressions /// </summary> public static void Convert(AstNode ast, MethodSource currentMethod, AssemblyCompiler compiler) { var typeSystem = compiler.Module.TypeSystem; // Expand typeof foreach (var node in ast.GetSelfAndChildrenRecursive<AstExpression>(x => x.Code == AstCode.TypeOf)) { var type = (XTypeReference) node.Operand; var typeHelperType = compiler.GetDot42InternalType(InternalConstants.TypeHelperName).Resolve(); var loadExpr = LoadTypeForGenericInstance(node.SourceLocation, currentMethod, type, compiler, typeHelperType, typeSystem, TypeConversion.EnsureTrueOrMarkerType); node.CopyFrom(loadExpr); } // Expand instanceOf foreach (var node in ast.GetSelfAndChildrenRecursive<AstExpression>(x => x.Code == AstCode.SimpleInstanceOf)) { var type = (XTypeReference)node.Operand; var gp = type as XGenericParameter; if (gp == null) continue; var typeHelperType = compiler.GetDot42InternalType(InternalConstants.TypeHelperName).Resolve(); var loadExpr = LoadTypeForGenericInstance(node.SourceLocation, currentMethod, type, compiler, typeHelperType, typeSystem, TypeConversion.EnsureRuntimeType); //// both types are boxed, no need for conversion. var typeType = compiler.GetDot42InternalType("System", "Type").Resolve(); var isInstanceOfType = typeType.Methods.Single(n => n.Name == "JavaIsInstance" && n.Parameters.Count == 1); var call = new AstExpression(node.SourceLocation, AstCode.Call, isInstanceOfType, loadExpr, node.Arguments[0]); node.CopyFrom(call); } // Expand newarr foreach (var node in ast.GetSelfAndChildrenRecursive<AstExpression>(x => x.Code == AstCode.Newarr)) { var type = (XTypeReference)node.Operand; if (!type.IsDefinitionOrReferenceOrPrimitive()) { // Resolve type to a Class<?> var typeHelperType = compiler.GetDot42InternalType(InternalConstants.TypeHelperName).Resolve(); // while having primitive arrays for primitive types would be nice, a lot of boxing and unboxing // would be needed. only for-primitive-specialized generic classes we could optimize this. var ldType = LoadTypeForGenericInstance(node.SourceLocation, currentMethod, type, compiler, typeHelperType, typeSystem, TypeConversion.EnsureRuntimeType); var newInstanceExpr = new AstExpression(node.SourceLocation, AstCode.ArrayNewInstance, null, ldType, node.Arguments[0]) { ExpectedType = typeSystem.Object }; var arrayType = new XArrayType(type); var cast = new AstExpression(node.SourceLocation, AstCode.SimpleCastclass, arrayType, newInstanceExpr) { ExpectedType = arrayType }; node.CopyFrom(cast); } } // Add generic instance call arguments foreach (var node in ast.GetSelfAndChildrenRecursive<AstExpression>(x => x.Code.IsCall())) { var method = (XMethodReference)node.Operand; if (method.DeclaringType.IsArray) continue; XMethodDefinition methodDef; if (!method.TryResolve(out methodDef)) continue; if (methodDef.HasDexNativeAttribute()) continue; if (methodDef.NeedsGenericInstanceTypeParameter) { // Add generic instance type parameter value var arg = CreateGenericInstanceCallArguments(node.SourceLocation, method.DeclaringType, currentMethod, compiler); node.Arguments.AddRange(arg); node.GenericInstanceArgCount += arg.Count; } if (methodDef.NeedsGenericInstanceMethodParameter) { // Add generic instance method parameter var arg = CreateGenericInstanceCallArguments(node.SourceLocation, method, currentMethod, compiler); node.Arguments.AddRange(arg); node.GenericInstanceArgCount += arg.Count; } } // Add generic instance Delegate arguments for static methods. foreach (var node in ast.GetSelfAndChildrenRecursive<AstExpression>(x => x.Code == AstCode.Delegate)) { var delegateInfo = (Tuple<XTypeDefinition, XMethodReference>)node.Operand; var genMethodDef = delegateInfo.Item2 as IXGenericInstance; var genTypeDef = delegateInfo.Item2.DeclaringType as IXGenericInstance; // Add generic instance type parameter value, if method is static if (genTypeDef != null && delegateInfo.Item2.Resolve().IsStatic) { var arg = CreateGenericInstanceCallArguments(node.SourceLocation, delegateInfo.Item2.DeclaringType, currentMethod, compiler); node.Arguments.AddRange(arg); node.GenericInstanceArgCount += arg.Count; } // add generic method type parameter value. if (genMethodDef != null) { var arg = CreateGenericInstanceCallArguments(node.SourceLocation, delegateInfo.Item2, currentMethod, compiler); node.Arguments.AddRange(arg); node.GenericInstanceArgCount += arg.Count; } } // Convert NewObj when needed foreach (var node in ast.GetSelfAndChildrenRecursive<AstExpression>(x => x.Code == AstCode.Newobj)) { var ctorRef = (XMethodReference)node.Operand; var declaringType = ctorRef.DeclaringType; if (declaringType.IsArray) { // New multi dimensional array // Get element type var elemType = ((XArrayType) declaringType).ElementType; var typeExpr = new AstExpression(node.SourceLocation, AstCode.TypeOf, elemType); // Create dimensions array var intArrayType = new XArrayType(typeSystem.Int); var dimArrayExpr = new AstExpression(node.SourceLocation, AstCode.InitArrayFromArguments, intArrayType, node.Arguments).SetType(intArrayType); // Call java.lang.reflect.Array.newInstance(type, int[]) var newInstanceExpr = new AstExpression(node.SourceLocation, AstCode.ArrayNewInstance2, null, typeExpr, dimArrayExpr).SetType(typeSystem.Object); // Cast to correct type var cast = new AstExpression(node.SourceLocation, AstCode.SimpleCastclass, declaringType, newInstanceExpr).SetType(declaringType); // Replace node node.CopyFrom(cast); } else { // Normal "new object" XMethodDefinition ctorDef; if (ctorRef.TryResolve(out ctorDef) && ctorDef.NeedsGenericInstanceTypeParameter) { // Add generic instance type parameter value var arg = CreateGenericInstanceCallArguments(node.SourceLocation, ctorRef.DeclaringType, currentMethod, compiler); node.Arguments.AddRange(arg); node.GenericInstanceArgCount += arg.Count; } } } }
/// <summary> /// Generate code for a call to a method of an array type. /// </summary> private bool TryVisitArrayTypeMethodCallExpression(AstExpression node, XMethodReference ilMethodRef, List<RLRange> args, AstNode parent, out RLRange result) { var methodName = ilMethodRef.Name; var dimensions = (methodName == "Set") ? args.Count - 2 : args.Count - 1; // Get all but last dimensions var arr = frame.AllocateTemp(FrameworkReferences.Object); var first = this.Add(node.SourceLocation, RCode.Move_object, arr, args[0].Result); for (var d = 0; d < dimensions - 1; d++) { this.Add(node.SourceLocation, RCode.Aget_object, arr, arr, args[d + 1].Result); } // Get/Set value switch (methodName) { case "Get": { var valueType = node.GetResultType(); var lastIndexArg = args[args.Count - 1]; var agetCode = new XArrayType(valueType).AGet(); var resultReg = frame.AllocateTemp(valueType.GetReference(targetPackage)); var last = this.Add(node.SourceLocation, agetCode, resultReg, arr, lastIndexArg.Result); result = new RLRange(first, last, resultReg); return true; } case "Set": { var valueType = node.Arguments[node.Arguments.Count - 1].GetResultType(); var lastIndexArg = args[args.Count - 2]; var aputCode = new XArrayType(valueType).APut(); // Perform type conversion if needed bool isConverted; var valueR = args[args.Count - 1].Result; var converted = this.ConvertTypeBeforeStore(node.SourceLocation, valueType, valueType, valueR, targetPackage, frame, compiler, out isConverted); if (isConverted) valueR = converted.Result; var last = this.Add(node.SourceLocation, aputCode, valueR, arr, lastIndexArg.Result); result = new RLRange(first, last, arr); return true; } default: result = null; return false; } }
/// <summary> /// Add generic instance field initialization code. /// </summary> private static void AddGenericInstanceFieldInitializationCode(MethodSource source, AstBlock ast, XTypeSystem typeSystem) { int paramCount = source.Method.DeclaringType.GenericParameters.Count; if (paramCount > InternalConstants.GenericTypeParametersAsArrayThreshold) { var xArrayType = new XArrayType(typeSystem.Type); var loadExpr = new AstExpression(ast.SourceLocation, AstCode.LdGenericInstanceTypeArgument, 0) {ExpectedType = xArrayType}; var initExpr = new AstExpression(ast.SourceLocation, AstCode.StGenericInstanceField, 0, loadExpr) { ExpectedType = xArrayType }; InsertAfter(ast, null, new[] {initExpr}); } else { InsertAfter(ast, null, Enumerable.Range(0, paramCount).Select(i => new AstExpression(ast.SourceLocation, AstCode.StGenericInstanceField, i, new AstExpression(ast.SourceLocation, AstCode.LdGenericInstanceTypeArgument, i) { ExpectedType = typeSystem.Type }) { ExpectedType = typeSystem.Type })); } }
/// <summary> /// Optimize expressions /// </summary> public static void Convert(DecompilerContext context, AstBlock ast, AssemblyCompiler compiler) { // Convert stobj/stind_ref foreach (var node in ast.GetExpressions(x => (x.Arguments.Count == 2) && ((x.Code == AstCode.Stobj) || (x.Code == AstCode.Stind_Ref)))) { var addrNode = node.Arguments[0]; var valueNode = node.Arguments[1]; AstVariable variable; if ((addrNode.GetResultType().IsByReference) && addrNode.Match(AstCode.Ldloc, out variable)) { if (variable.IsThis && valueNode.Match(AstCode.DefaultValue)) { // Struct init : this() node.CopyFrom(new AstExpression(node.SourceLocation, AstCode.Nop, null)); } else if (!variable.IsThis) { // Convert byref type to array type var addrType = (XByReferenceType) addrNode.GetResultType(); var arrayType = new XArrayType(addrType.ElementType); addrNode.ExpectedType = arrayType; addrNode.InferredType = arrayType; // Convert to stelem array, index, value var int32Type = compiler.Module.TypeSystem.Int; node.Arguments.Insert(1, new AstExpression(node.SourceLocation, AstCode.Ldc_I4, 0).SetType(int32Type)); node.Code = arrayType.ElementType.GetStElemCode(); } else { // Convert to stloc } } } // Convert ldobj var resetTypes = false; var processed = new HashSet<AstExpression>(); foreach (var pair in ast.GetExpressionPairs()) { var node = pair.Expression; if ((node.Arguments.Count == 1) && ((node.Code == AstCode.Ldobj) || (node.Code == AstCode.Ldind_Ref))) { var parent = pair.Parent; var useAsValue = true; var isCallArgument = (parent != null) && (parent.Code.IsCall()); var isBoxArgument = (parent != null) && (parent.Match(AstCode.Box)); if (isCallArgument && (node.Code == AstCode.Ldobj)) { if (IsArgByRefOrOut(node, parent)) { useAsValue = false; } } if (isBoxArgument) { var boxType = (XTypeReference) parent.Operand; if (!boxType.IsGenericParameter) { useAsValue = false; } } var ldlocNode = node.Arguments[0]; processed.Add(ldlocNode); var addrNodeType = ldlocNode.GetResultType(); if (ldlocNode.MatchThis()) { useAsValue = false; } if (useAsValue) { if ((addrNodeType.IsByReference) && (ldlocNode.Code == AstCode.Ldloc)) { // Convert byref type to array type var addrType = (XByReferenceType)ldlocNode.GetResultType(); var arrayType = new XArrayType(addrType.ElementType); ldlocNode.ExpectedType = arrayType; ldlocNode.InferredType = arrayType; // Convert to ldelem array, index, value var int32Type = compiler.Module.TypeSystem.Int; node.Arguments.Insert(1, new AstExpression(node.SourceLocation, AstCode.Ldc_I4, 0).SetType(int32Type)); node.Code = arrayType.ElementType.GetLdElemCode(); node.SetType(arrayType.ElementType); resetTypes = true; } } else if (isCallArgument && (ldlocNode.Code == AstCode.Ldloc)) { var typeRef = (XTypeReference)node.Operand; XTypeDefinition typeDef; if ((typeRef != null) && typeRef.TryResolve(out typeDef) && typeDef.IsValueType && !typeDef.IsPrimitive) { // Replace by ldloc node.Code = AstCode.Ldloc; node.Operand = ldlocNode.Operand; node.Arguments.Clear(); } } } else if ((node.Code == AstCode.Ldloc) && ((AstVariable)node.Operand).IsParameter && (node.GetResultType().IsByReference)) { var parent = pair.Parent; if ((parent != null) && (parent.Code == AstCode.Ldobj)) { continue; } var useAsValue = true; var isCallArgument = (parent != null) && (parent.Code.IsCall()); var isBoxArgument = (parent != null) && (parent.Match(AstCode.Box)); if (isCallArgument) { if (IsArgByRefOrOut(node, parent)) { useAsValue = false; } } if (isBoxArgument) { useAsValue = false; } if (node.MatchThis()) { useAsValue = false; } if (useAsValue) { // Convert byref type to array type var addrType = (XByReferenceType) node.GetResultType(); var arrayType = new XArrayType(addrType.ElementType); var clone = new AstExpression(node).SetType(arrayType); // Convert to ldelem array, index, value var int32Type = compiler.Module.TypeSystem.Int; node.SetArguments(clone, new AstExpression(node.SourceLocation, AstCode.Ldc_I4, 0).SetType(int32Type)); node.Code = arrayType.ElementType.GetLdElemCode(); node.SetType(arrayType.ElementType); resetTypes = true; } } } if (resetTypes) { TypeAnalysis.Run(context, ast); } }
/// <summary> /// Default ctor /// </summary> public InitArrayData(XArrayType arrayType, Array values) { this.arrayType = arrayType; this.values = values; }
/// <summary> /// Optimize expressions /// </summary> public static void Convert(AstNode ast, MethodSource currentMethod, AssemblyCompiler compiler) { var typeSystem = compiler.Module.TypeSystem; // Expand typeof foreach (var node in ast.GetSelfAndChildrenRecursive<AstExpression>(x => x.Code == AstCode.TypeOf)) { var type = (XTypeReference) node.Operand; var typeHelperType = compiler.GetDot42InternalType(InternalConstants.TypeHelperName).Resolve(); var loadExpr = LoadTypeForGenericInstance(node.SourceLocation, currentMethod, type, typeHelperType, typeSystem, false); node.CopyFrom(loadExpr); } // Expand newarr foreach (var node in ast.GetSelfAndChildrenRecursive<AstExpression>(x => x.Code == AstCode.Newarr)) { var type = (XTypeReference)node.Operand; if (!type.IsDefinitionOrReferenceOrPrimitive()) { // Resolve type to a Class<?> var typeHelperType = compiler.GetDot42InternalType(InternalConstants.TypeHelperName).Resolve(); var ldType = LoadTypeForGenericInstance(node.SourceLocation, currentMethod, type, typeHelperType, typeSystem, false); var newInstanceExpr = new AstExpression(node.SourceLocation, AstCode.ArrayNewInstance, null, ldType, node.Arguments[0]) { ExpectedType = typeSystem.Object }; var arrayType = new XArrayType(type); var cast = new AstExpression(node.SourceLocation, AstCode.SimpleCastclass, arrayType, newInstanceExpr) { ExpectedType = arrayType }; node.CopyFrom(cast); } } // Add generic instance call arguments foreach (var node in ast.GetSelfAndChildrenRecursive<AstExpression>(x => x.Code.IsCall())) { var method = (XMethodReference)node.Operand; if (method.DeclaringType.IsArray) continue; XMethodDefinition methodDef; if (!method.TryResolve(out methodDef)) continue; if (methodDef.HasDexNativeAttribute()) continue; if (methodDef.NeedsGenericInstanceTypeParameter) { // Add generic instance type parameter value var arg = CreateGenericInstance(node.SourceLocation, method.DeclaringType, currentMethod, compiler); node.Arguments.Add(arg); node.GenericInstanceArgCount++; } if (methodDef.NeedsGenericInstanceMethodParameter) { // Add generic instance method parameter var arg = CreateGenericInstance(node.SourceLocation, method, currentMethod, compiler); node.Arguments.Add(arg); node.GenericInstanceArgCount++; } } // Convert NewObj when needed foreach (var node in ast.GetSelfAndChildrenRecursive<AstExpression>(x => x.Code == AstCode.Newobj)) { var ctorRef = (XMethodReference)node.Operand; var declaringType = ctorRef.DeclaringType; if (declaringType.IsArray) { // New multi dimensional array // Get element type var elemType = ((XArrayType) declaringType).ElementType; var typeExpr = new AstExpression(node.SourceLocation, AstCode.TypeOf, elemType); // Create dimensions array var intArrayType = new XArrayType(typeSystem.Int); var dimArrayExpr = new AstExpression(node.SourceLocation, AstCode.InitArrayFromArguments, intArrayType, node.Arguments).SetType(intArrayType); // Call java.lang.reflect.Array.newInstance(type, int[]) var newInstanceExpr = new AstExpression(node.SourceLocation, AstCode.ArrayNewInstance2, null, typeExpr, dimArrayExpr).SetType(typeSystem.Object); // Cast to correct type var cast = new AstExpression(node.SourceLocation, AstCode.SimpleCastclass, declaringType, newInstanceExpr).SetType(declaringType); // Replace node node.CopyFrom(cast); } else { // Normal "new object" XMethodDefinition ctorDef; if (ctorRef.TryResolve(out ctorDef) && ctorDef.NeedsGenericInstanceTypeParameter) { // Add generic instance type parameter value var arg = CreateGenericInstance(node.SourceLocation, ctorRef.DeclaringType, currentMethod, compiler); node.Arguments.Add(arg); node.GenericInstanceArgCount++; } } } }