/// <summary> /// Optimize expressions /// </summary> public static void Convert(AstNode ast) { // Expand typeof foreach (var pair in ast.GetExpressionPairs()) { var node = pair.Expression; switch (node.Code) { case AstCode.Ldfld: //case AstCode.Ldsfld: // NOT YET { var field = (XFieldReference) node.Operand; var clone = new AstExpression(node); node.SetCode(AstCode.UnboxFromGeneric).SetArguments(clone).Operand = field.FieldType; } break; case AstCode.Call: case AstCode.Calli: case AstCode.Callvirt: { var method = (XMethodReference)node.Operand; if ((!method.ReturnType.IsVoid()) && (pair.Parent != null)) { var clone = new AstExpression(node); node.SetCode(AstCode.UnboxFromGeneric).SetArguments(clone).Operand = method.ReturnType; } } break; } } }
/// <summary> /// Optimize expressions /// </summary> public static void Convert(AstNode ast) { // Expand typeof foreach (var pair in ast.GetExpressionPairs()) { var node = pair.Expression; switch (node.Code) { case AstCode.Ldfld: //case AstCode.Ldsfld: // NOT YET { var field = (XFieldReference)node.Operand; var clone = new AstExpression(node); node.SetCode(AstCode.UnboxFromGeneric).SetArguments(clone).Operand = field.FieldType; } break; case AstCode.Call: case AstCode.Calli: case AstCode.Callvirt: { var method = (XMethodReference)node.Operand; if ((!method.ReturnType.IsVoid()) && (pair.Parent != null)) { var clone = new AstExpression(node); node.SetCode(AstCode.UnboxFromGeneric).SetArguments(clone).Operand = method.ReturnType; } } break; } } }
/// <summary> /// Optimize expressions /// </summary> public static void Convert(AstNode ast, MethodSource currentMethod, XTypeSystem typeSystem) { // Expand typeof foreach (var pair in ast.GetExpressionPairs()) { var node = pair.Expression; switch (node.Code) { case AstCode.Ldfld: //case AstCode.Ldsfld: // NOT YET { var field = (XFieldReference) node.Operand; UnboxIfGeneric(field.FieldType, node, typeSystem); } break; case AstCode.Stfld: { var field = (XFieldReference)node.Operand; BoxIfGeneric(field.FieldType, node.Arguments[1]); } break; case AstCode.Call: case AstCode.Calli: case AstCode.Callvirt: { var method = (XMethodReference)node.Operand; if ((!method.ReturnType.IsVoid()) && (pair.Parent != null)) { UnboxIfGeneric(method.ReturnType, node, typeSystem); } } break; case AstCode.Ret: { if (node.Arguments.Count > 0) { var expectedType = currentMethod.Method.ReturnType; BoxIfGeneric(expectedType, node.Arguments[0]); } } break; case AstCode.ByRefArray: case AstCode.ByRefOutArray: { if (node.Arguments.Count > 1) { var originalType = (XTypeReference) node.Arguments[1].Operand; UnboxByRefIfGeneric(originalType, node.StoreByRefExpression, typeSystem); } } break; } } }
/// <summary> /// Optimize expressions /// </summary> public static void Convert(AstNode ast) { foreach (var pair in ast.GetExpressionPairs()) { var node = pair.Expression; switch (node.Code) { case AstCode.Ldc_I4: { var constType = node.GetResultType(); if (constType.IsByte()) { node.Operand = System.Convert.ToInt32(node.Operand) & 0xFF; } else if (constType.IsUInt16()) { node.Operand = System.Convert.ToInt32(node.Operand) & 0xFFFF; } } break; case AstCode.Ldloc: { var variable = (AstVariable)node.Operand; var varType = variable.Type; ConvertIfNeeded(node, varType, pair.Parent); } break; case AstCode.Ldfld: case AstCode.Ldsfld: { var field = (XFieldReference)node.Operand; var fieldType = field.FieldType; ConvertIfNeeded(node, fieldType, pair.Parent); } break; case AstCode.Ldelem_U1: case AstCode.Ldelem_U2: { var arrayType = (XArrayType)node.Arguments[0].GetResultType(); var elementType = arrayType.ElementType; ConvertIfNeeded(node, elementType, pair.Parent); } break; } } }
/// <summary> /// Optimize expressions /// </summary> public static void Convert(AstNode ast) { foreach (var pair in ast.GetExpressionPairs()) { var node = pair.Expression; switch (node.Code) { case AstCode.Ldc_I4: { var constType = node.GetResultType(); if (constType.IsByte()) { node.Operand = System.Convert.ToInt32(node.Operand) & 0xFF; } else if (constType.IsUInt16()) { node.Operand = System.Convert.ToInt32(node.Operand) & 0xFFFF; } } break; case AstCode.Ldloc: { var variable = (AstVariable) node.Operand; var varType = variable.Type; ConvertIfNeeded(node, varType, pair.Parent); } break; case AstCode.Ldfld: case AstCode.Ldsfld: { var field = (XFieldReference) node.Operand; var fieldType = field.FieldType; ConvertIfNeeded(node, fieldType, pair.Parent); } break; case AstCode.Ldelem_U1: case AstCode.Ldelem_U2: { var arrayType = (XArrayType) node.Arguments[0].GetResultType(); var elementType = arrayType.ElementType; ConvertIfNeeded(node, elementType, pair.Parent); } break; } } }
/// <summary> /// Optimize expressions /// </summary> public static void Convert(AstNode ast, AssemblyCompiler compiler) { foreach (var pair in ast.GetExpressionPairs()) { var node = pair.Expression; switch (node.Code) { case AstCode.Call: case AstCode.Calli: case AstCode.Callvirt: var methodRef = (XMethodReference)node.Operand; XMethodDefinition method; if (methodRef.TryResolve(out method)) { var targetType = method.DeclaringType; var prefix = node.GetPrefix(AstCode.Constrained); if (prefix != null) { // Calls to object::ToString for value types have a constrained prefix with the target type in the prefix operand. var prefixTypeRef = (XTypeReference)prefix.Operand; XTypeDefinition prefixTypeDef; if (prefixTypeRef.TryResolve(out prefixTypeDef)) { targetType = prefixTypeDef; } } if (targetType.IsValueType && !targetType.IsPrimitive && !/*targetType*/ method.DeclaringType.IsSystemNullable()) { if (method.IsConstructor && (!node.Arguments[0].MatchThis())) { // Convert ctor call ConvertCtorCall(node, methodRef); } else { // Convert normal method call for (var i = 0; i < node.Arguments.Count; i++) { ProcessArgument(node, method, i, compiler.Module); } } } // Clone all struct arguments for (var i = 0; i < node.Arguments.Count; i++) { CloneStructArgument(node, method, i); } } break; case AstCode.DefaultValue: { var typeRef = (XTypeReference)node.Operand; XTypeDefinition type; if (typeRef.TryResolve(out type)) { if (type.IsStruct) { var defaultCtor = GetDefaultValueCtor(type); ConvertDefaultValue(node, defaultCtor); } } } break; case AstCode.Newarr: { var typeRef = (XTypeReference)node.Operand; XTypeDefinition type; if (typeRef.TryResolve(out type) && type.IsValueType && !type.IsPrimitive && !type.IsSystemNullable()) { var parentCode = (pair.Parent != null) ? pair.Parent.Code : AstCode.Nop; if (type.IsEnum) { // Initialize enum array if (parentCode != AstCode.InitEnumArray) // Avoid recursion { ConvertNewArrEnum(node); } } else { // Initialize struct array if (parentCode != AstCode.InitStructArray) // Avoid recursion { var defaultCtor = GetDefaultValueCtor(type); ConvertNewArrStruct(node, defaultCtor); } } } } break; case AstCode.Ldloca: node.Code = AstCode.Ldloc; break; case AstCode.Ldflda: node.Code = AstCode.Ldfld; break; case AstCode.Ldsflda: node.Code = AstCode.Ldsfld; break; case AstCode.Ldelema: node.Code = AstCode.Ldelem_Any; break; case AstCode.Ldobj: if ((node.Arguments.Count == 1) && (node.Arguments[0].Code == AstCode.Ldloc)) { node.CopyFrom(node.Arguments[0]); } break; case AstCode.Stelem_Any: { var arrayType = node.Arguments[0].GetResultType() as XArrayType; XTypeDefinition elementType; if ((arrayType != null) && (arrayType.ElementType.IsStruct(out elementType) && !elementType.IsImmutableStruct)) { // Call $Clone var cloneMethod = GetCloneMethod(elementType); var valueArg = node.Arguments[2]; if (IsCloneNeeded(valueArg)) { var clone = new AstExpression(node.SourceLocation, AstCode.Call, arrayType.ElementType.CreateReference(cloneMethod), valueArg); node.Arguments[2] = clone; } } } break; case AstCode.Stfld: case AstCode.Stsfld: { var field = (XFieldReference)node.Operand; XTypeDefinition fieldType; if (field.FieldType.IsStruct(out fieldType) && !fieldType.IsImmutableStruct) { // Call $Clone var cloneMethod = GetCloneMethod(fieldType); var valueArgIndex = node.Arguments.Count - 1; // Last argument var valueArg = node.Arguments[valueArgIndex]; if (IsCloneNeeded(valueArg)) { var clone = new AstExpression(node.SourceLocation, AstCode.Call, field.FieldType.CreateReference(cloneMethod), valueArg); node.Arguments[valueArgIndex] = clone; } } } break; case AstCode.Stloc: { var variable = (AstVariable)node.Operand; XTypeDefinition varType; if (variable.Type.IsStruct(out varType)) { if (variable.IsThis) { // Call this.$CopyFrom var copyFromMethod = GetCopyFromMethod(varType); node.Code = AstCode.Call; node.Operand = variable.Type.CreateReference(copyFromMethod); } else { if (!varType.IsImmutableStruct) { // Call $Clone var cloneMethod = GetCloneMethod(varType); var valueArgIndex = node.Arguments.Count - 1; // Last argument var valueArg = node.Arguments[valueArgIndex]; if (IsCloneNeeded(valueArg)) { var clone = new AstExpression(node.SourceLocation, AstCode.Call, variable.Type.CreateReference(cloneMethod), valueArg); node.Arguments[valueArgIndex] = clone; } } } } } break; case AstCode.Stobj: { var type = (XTypeReference)node.Operand; XTypeDefinition typeDef; if (type.IsStruct(out typeDef) && !typeDef.IsImmutableStruct) { // Convert to arg0.$CopyFrom(arg1) var copyFromMethod = GetCopyFromMethod(typeDef); node.Code = AstCode.Call; node.Operand = type.CreateReference(copyFromMethod); } } break; case AstCode.Box: if (node.Arguments.Count == 1) { var typeRef = (XTypeReference)node.Operand; XTypeDefinition type; if (typeRef.TryResolve(out type) && type.IsValueType && !type.IsPrimitive && !type.IsSystemNullable()) { var ldObjExpr = node.Arguments[0]; if ((ldObjExpr.Code == AstCode.Ldobj) && (ldObjExpr.Arguments.Count == 1)) { var ldThisExpr = ldObjExpr.Arguments[0]; if (ldThisExpr.MatchThis()) { // box(ldobj(ldthis)) -> ldthis // TODO: think about making a clone here. node.CopyFrom(ldThisExpr); } } } } break; case AstCode.Ret: if (node.Arguments.Count == 1) { var ldObjExpr = node.Arguments[0]; if ((ldObjExpr.Code == AstCode.Ldobj) && (ldObjExpr.Arguments.Count == 1)) { var typeRef = ldObjExpr.GetResultType(); XTypeDefinition type; if (typeRef.TryResolve(out type) && type.IsValueType && !type.IsPrimitive && !type.IsSystemNullable()) { var ldThisExpr = ldObjExpr.Arguments[0]; if (ldThisExpr.MatchThis()) { // box(ldobj(ldthis)) -> ldthis ldObjExpr.CopyFrom(ldThisExpr); } } } } break; } } }
/// <summary> /// Optimize expressions /// </summary> public static void Convert(AstNode ast, MethodSource currentMethod, XTypeSystem typeSystem) { // Expand typeof foreach (var pair in ast.GetExpressionPairs()) { var node = pair.Expression; switch (node.Code) { case AstCode.Ldfld: //case AstCode.Ldsfld: // NOT YET { var field = (XFieldReference) node.Operand; UnboxIfGeneric(field.FieldType, node, typeSystem); } break; case AstCode.Stfld: { var field = (XFieldReference)node.Operand; BoxIfGeneric(field.FieldType, node.Arguments[1]); } break; case AstCode.Call: case AstCode.Calli: case AstCode.Callvirt: { var method = (XMethodReference)node.Operand; if ((!method.ReturnType.IsVoid()) && (pair.Parent != null)) { UnboxIfGeneric(method.ReturnType, node, typeSystem); } } break; case AstCode.Ret: { if (node.Arguments.Count > 0) { var expectedType = currentMethod.Method.ReturnType; BoxIfGeneric(expectedType, node.Arguments[0]); } } break; case AstCode.Box: { var type = (XTypeReference)node.Operand; // Honestly, the whole Generics code seems to be quite // complex. I hope this fix does not break anything else. // Also: is there any sense in having two codes 'box' and 'boxtogeneric'? // The Rosyln compiler apparently uses 'box' instructions to satisfy // generic constraints. Not sure if this is the right place to handle // this. // What we want to achive is to perform this conversion code only if the // expected type is assignable from any of the constraints. As we do not // have an 'IsAssignableFrom' logic for XTypes, a simpler check must suffice. if (type.IsGenericParameter && ((XGenericParameter)type).Constraints.Any() && node.ExpectedType != null && !node.ExpectedType.IsPrimitive && !node.ExpectedType.IsGenericParameter) { // or just enter the required cast here??? node.Code = AstCode.BoxToGeneric; node.InferredType = node.ExpectedType; } } break; case AstCode.ByRefArray: case AstCode.ByRefOutArray: { if (node.Arguments.Count > 1) { var originalType = (XTypeReference) node.Arguments[1].Operand; UnboxByRefIfGeneric(originalType, node.StoreByRefExpression, typeSystem); } } break; } } }
/// <summary> /// Optimize expressions /// </summary> public static void Convert(AstNode ast, MethodSource currentMethod, XTypeSystem typeSystem) { // Expand typeof foreach (var pair in ast.GetExpressionPairs()) { var node = pair.Expression; switch (node.Code) { case AstCode.Ldfld: //case AstCode.Ldsfld: // NOT YET { var field = (XFieldReference)node.Operand; UnboxIfGeneric(field.FieldType, node, typeSystem); } break; case AstCode.Stfld: { var field = (XFieldReference)node.Operand; BoxIfGeneric(field.FieldType, node.Arguments[1]); } break; case AstCode.Call: case AstCode.Calli: case AstCode.Callvirt: { var method = (XMethodReference)node.Operand; if ((!method.ReturnType.IsVoid()) && (pair.Parent != null)) { UnboxIfGeneric(method.ReturnType, node, typeSystem); } } break; case AstCode.Ret: { if (node.Arguments.Count > 0) { var expectedType = currentMethod.Method.ReturnType; BoxIfGeneric(expectedType, node.Arguments[0]); } } break; case AstCode.Box: { var type = (XTypeReference)node.Operand; // Honestly, the whole Generics code seems to be quite // complex. I hope this fix does not break anything else. // Also: is there any sense in having two codes 'box' and 'boxtogeneric'? // The Rosyln compiler apparently uses 'box' instructions to satisfy // generic constraints. Not sure if this is the right place to handle // this. // What we want to achive is to perform this conversion code only if the // expected type is assignable from any of the constraints. As we do not // have an 'IsAssignableFrom' logic for XTypes, a simpler check must suffice. if (type.IsGenericParameter && ((XGenericParameter)type).Constraints.Any() && node.ExpectedType != null && !node.ExpectedType.IsPrimitive && !node.ExpectedType.IsGenericParameter) { // or just enter the required cast here??? node.Code = AstCode.BoxToGeneric; node.InferredType = node.ExpectedType; } } break; case AstCode.ByRefArray: case AstCode.ByRefOutArray: { if (node.Arguments.Count > 1) { var originalType = (XTypeReference)node.Arguments[1].Operand; UnboxByRefIfGeneric(originalType, node.StoreByRefExpression, typeSystem); } } break; } } }
/// <summary> /// Optimize expressions /// </summary> public static void Convert(AstNode ast, AssemblyCompiler compiler) { foreach (var pair in ast.GetExpressionPairs()) { var node = pair.Expression; switch (node.Code) { case AstCode.Call: case AstCode.Calli: case AstCode.Callvirt: var methodRef = (XMethodReference) node.Operand; XMethodDefinition method; if (methodRef.TryResolve(out method)) { var targetType = method.DeclaringType; var prefix = node.GetPrefix(AstCode.Constrained); if (prefix != null) { // Calls to object::ToString for value types have a constrained prefix with the target type in the prefix operand. var prefixTypeRef = (XTypeReference) prefix.Operand; XTypeDefinition prefixTypeDef; if (prefixTypeRef.TryResolve(out prefixTypeDef)) { targetType = prefixTypeDef; } } if (targetType.IsValueType && !targetType.IsPrimitive && ! /*targetType*/method.DeclaringType.IsSystemNullable()) { if (method.IsConstructor && (!node.Arguments[0].MatchThis())) { // Convert ctor call ConvertCtorCall(node, methodRef); } else { // Convert normal method call for (var i = 0; i < node.Arguments.Count; i++) { ProcessArgument(node, method, i, compiler.Module); } } } // Clone all struct arguments for (var i = 0; i < node.Arguments.Count; i++) { CloneStructArgument(node, method, i); } } break; case AstCode.DefaultValue: { var typeRef = (XTypeReference) node.Operand; XTypeDefinition type; if (typeRef.TryResolve(out type) && type.IsValueType && !type.IsPrimitive && !type.IsEnum && !type.IsSystemNullable()) { var defaultCtor = GetDefaultValueCtor(type); ConvertDefaultValue(node, defaultCtor); } } break; case AstCode.Newarr: { var typeRef = (XTypeReference) node.Operand; XTypeDefinition type; if (typeRef.TryResolve(out type) && type.IsValueType && !type.IsPrimitive && !type.IsSystemNullable()) { var parentCode = (pair.Parent != null) ? pair.Parent.Code : AstCode.Nop; if (type.IsEnum) { // Initialize enum array if (parentCode != AstCode.InitEnumArray) // Avoid recursion { ConvertNewArrEnum(node); } } else { // Initialize struct array if (parentCode != AstCode.InitStructArray) // Avoid recursion { var defaultCtor = GetDefaultValueCtor(type); ConvertNewArrStruct(node, defaultCtor); } } } } break; case AstCode.Ldloca: node.Code = AstCode.Ldloc; break; case AstCode.Ldflda: node.Code = AstCode.Ldfld; break; case AstCode.Ldsflda: node.Code = AstCode.Ldsfld; break; case AstCode.Ldelema: node.Code = AstCode.Ldelem_Any; break; case AstCode.Ldobj: if ((node.Arguments.Count == 1) && (node.Arguments[0].Code == AstCode.Ldloc)) { node.CopyFrom(node.Arguments[0]); } break; case AstCode.Stelem_Any: { var arrayType = node.Arguments[0].GetResultType() as XArrayType; XTypeDefinition elementType; if ((arrayType != null) && (arrayType.ElementType.IsStruct(out elementType))) { // Call $Clone var cloneMethod = GetCloneMethod(elementType); var valueArg = node.Arguments[2]; if (IsCloneNeeded(valueArg)) { var clone = new AstExpression(node.SourceLocation, AstCode.Call, arrayType.ElementType.CreateReference(cloneMethod), valueArg); node.Arguments[2] = clone; } } } break; case AstCode.Stfld: case AstCode.Stsfld: { var field = (XFieldReference) node.Operand; XTypeDefinition fieldType; if (field.FieldType.IsStruct(out fieldType)) { // Call $Clone var cloneMethod = GetCloneMethod(fieldType); var valueArgIndex = node.Arguments.Count - 1; // Last argument var valueArg = node.Arguments[valueArgIndex]; if (IsCloneNeeded(valueArg)) { var clone = new AstExpression(node.SourceLocation, AstCode.Call, field.FieldType.CreateReference(cloneMethod), valueArg); node.Arguments[valueArgIndex] = clone; } } } break; case AstCode.Stloc: { var variable = (AstVariable) node.Operand; XTypeDefinition varType; if (variable.Type.IsStruct(out varType)) { if (variable.IsThis) { // Call this.$CopyFrom var copyFromMethod = GetCopyFromMethod(varType); node.Code = AstCode.Call; node.Operand = variable.Type.CreateReference(copyFromMethod); } else { // Call $Clone var cloneMethod = GetCloneMethod(varType); var valueArgIndex = node.Arguments.Count - 1; // Last argument var valueArg = node.Arguments[valueArgIndex]; if (IsCloneNeeded(valueArg)) { var clone = new AstExpression(node.SourceLocation, AstCode.Call, variable.Type.CreateReference(cloneMethod), valueArg); node.Arguments[valueArgIndex] = clone; } } } } break; case AstCode.Stobj: { var type = (XTypeReference) node.Operand; XTypeDefinition typeDef; if (type.IsStruct(out typeDef)) { // Convert to arg0.$CopyFrom(arg1) var copyFromMethod = GetCopyFromMethod(typeDef); node.Code = AstCode.Call; node.Operand = type.CreateReference(copyFromMethod); } } break; case AstCode.Box: if (node.Arguments.Count == 1) { var typeRef = (XTypeReference) node.Operand; XTypeDefinition type; if (typeRef.TryResolve(out type) && type.IsValueType && !type.IsPrimitive && !type.IsSystemNullable()) { var ldObjExpr = node.Arguments[0]; if ((ldObjExpr.Code == AstCode.Ldobj) && (ldObjExpr.Arguments.Count == 1)) { var ldThisExpr = ldObjExpr.Arguments[0]; if (ldThisExpr.MatchThis()) { // box(ldobj(ldthis)) -> ldthis node.CopyFrom(ldThisExpr); } } } } break; case AstCode.Ret: if (node.Arguments.Count == 1) { var ldObjExpr = node.Arguments[0]; if ((ldObjExpr.Code == AstCode.Ldobj) && (ldObjExpr.Arguments.Count == 1)) { var typeRef = ldObjExpr.GetResultType(); XTypeDefinition type; if (typeRef.TryResolve(out type) && type.IsValueType && !type.IsPrimitive && !type.IsSystemNullable()) { var ldThisExpr = ldObjExpr.Arguments[0]; if (ldThisExpr.MatchThis()) { // box(ldobj(ldthis)) -> ldthis ldObjExpr.CopyFrom(ldThisExpr); } } } } break; } } }