/// <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 })); } }
private bool TransformMultidimensionalArrayInitializers(List <AstNode> body, AstExpression expr, int pos) { AstVariable v; AstExpression newarrExpr; XMethodReference ctor; List <AstExpression> ctorArgs; XArrayType arrayType; if (expr.Match(AstCode.Stloc, out v, out newarrExpr) && newarrExpr.Match(AstCode.Newobj, out ctor, out ctorArgs) && (arrayType = (ctor.DeclaringType as XArrayType)) != null && arrayType.Rank == ctorArgs.Count) { // Clone the type, so we can muck about with the Dimensions var arrayLengths = new int[arrayType.Rank]; var dimensions = new XArrayDimension[arrayType.Rank]; for (int i = 0; i < arrayType.Rank; i++) { if (!ctorArgs[i].Match(AstCode.Ldc_I4, out arrayLengths[i])) { return(false); } if (arrayLengths[i] <= 0) { return(false); } dimensions[i] = new XArrayDimension(0, arrayLengths[i]); } arrayType = new XArrayType(arrayType.ElementType, dimensions); var totalElements = arrayLengths.Aggregate(1, (t, l) => t * l); Array newArr; int initArrayPos; if (ForwardScanInitializeArrayRuntimeHelper(body, pos + 1, v, arrayType, totalElements, out newArr, out initArrayPos)) { body[pos] = new AstExpression(expr.SourceLocation, AstCode.Stloc, v, new AstExpression(expr.SourceLocation, AstCode.InitArray, new InitArrayData(arrayType, newArr))); body.RemoveAt(initArrayPos); return(true); } } return(false); }
/// <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> /// 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); } }
bool TransformArrayInitializers(List <AstNode> body, AstExpression expr, int pos) { AstVariable v, v3; AstExpression newarrExpr; XTypeReference elementType; AstExpression lengthExpr; int arrayLength; if (expr.Match(AstCode.Stloc, out v, out newarrExpr) && newarrExpr.Match(AstCode.Newarr, out elementType, out lengthExpr) && lengthExpr.Match(AstCode.Ldc_I4, out arrayLength) && arrayLength > 0) { Array newArr; int initArrayPos; if (ForwardScanInitializeArrayRuntimeHelper(body, pos + 1, v, elementType, arrayLength, out newArr, out initArrayPos)) { var arrayType = new XArrayType(elementType, new XArrayDimension(0, arrayLength)); body[pos] = new AstExpression(expr.SourceLocation, AstCode.Stloc, v, new AstExpression(expr.SourceLocation, AstCode.InitArray, new InitArrayData(arrayType, newArr))); body.RemoveAt(initArrayPos); } #if !NOTUSED // Put in a limit so that we don't consume too much memory if the code allocates a huge array // and populates it extremely sparsly. However, 255 "null" elements in a row actually occur in the Mono C# compiler! const int maxConsecutiveDefaultValueExpressions = 0; // 300; var operands = new List <AstExpression>(); int numberOfInstructionsToRemove = 0; for (int j = pos + 1; j < body.Count; j++) { var nextExpr = body[j] as AstExpression; int arrayPos; if (nextExpr != null && nextExpr.Code.IsStoreToArray() && nextExpr.Arguments[0].Match(AstCode.Ldloc, out v3) && v == v3 && nextExpr.Arguments[1].Match(AstCode.Ldc_I4, out arrayPos) && arrayPos >= operands.Count && arrayPos <= operands.Count + maxConsecutiveDefaultValueExpressions) { while (operands.Count < arrayPos) { operands.Add(new AstExpression(expr.SourceLocation, AstCode.DefaultValue, elementType)); } operands.Add(nextExpr.Arguments[2]); numberOfInstructionsToRemove++; } else { break; } } /*if (operands.Count == arrayLength) { * var arrayType = new XArrayType(elementType, new XArrayDimension(0, arrayLength)); * expr.Arguments[0] = new AstExpression(expr.SourceLocation, AstCode.InitArray, arrayType, operands); * body.RemoveRange(pos + 1, numberOfInstructionsToRemove); * * new AstInlining(method).InlineIfPossible(body, ref pos); * return true; * }*/ #endif } return(false); }
/// <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++; } } } }
/// <summary> /// Default ctor /// </summary> public InitArrayData(XArrayType arrayType, Array values) { this.arrayType = arrayType; this.values = values; }