private bool TryInferVariableType(CilVariable variable) { // Do not update the type of the flags variable. if (_context.FlagVariable == variable) { return(false); } // Collect expected types. var expectedTypes = CollectExpectedTypes(variable); ITypeDescriptor newVariableType = null; if (expectedTypes.Any(t => t.IsTypeOf("System", "Array"))) { newVariableType = TryInferArrayType(variable); } if (newVariableType == null) { newVariableType = _helper.GetCommonBaseType(expectedTypes); } return(TrySetVariableType(variable, newVariableType)); }
private bool TrySetVariableType(CilVariable variable, ITypeDescriptor variableType) { if (variableType != null && variable.VariableType.FullName != variableType.FullName) { var newType = _context.TargetImage.TypeSystem.GetMscorlibType(variableType) ?? _context.ReferenceImporter.ImportTypeSignature(variableType.ToTypeSignature()); variable.VariableType = newType; // Update the expression type of all references to the variable. foreach (var use in variable.UsedBy) { use.ExpressionType = use.IsReference ? new ByReferenceTypeSignature(newType) : newType; } // Update the expected type of all expressions that are assigned to the variable. foreach (var assign in variable.AssignedBy) { assign.Value.ExpectedType = newType; } return(true); } return(false); }
/// <inheritdoc /> public IConcreteValue this[IVariable variable] { get { if (!_variables.TryGetValue(variable, out var value)) { value = variable switch { CilVariable cilVariable => _valueFactory.CreateValue(cilVariable.Variable.VariableType, false), CilParameter cilParameter => _valueFactory.CreateValue(cilParameter.Parameter.ParameterType, false), _ => throw new NotSupportedException($"IVariable implementation {variable.GetType()} is not supported.") }; _variables[variable] = value; } return(value); } set { if (!(variable is CilParameter) && !(variable is CilVariable)) { throw new NotSupportedException($"IVariable implementation {variable.GetType()} is not supported."); } _variables[variable] = value; } }
public CodeGenerationContext(CilMethodBody methodBody, VMConstants constants, CilVariable flagVariable, TypeDefinition flagHelperType) { MethodBody = methodBody; Constants = constants; _flagVariable = flagVariable; VmHelperType = flagHelperType; ReferenceImporter = new ReferenceImporter(TargetModule); _arg0 = new CilVariable("__arg0", TargetModule.CorLibTypeFactory.UInt32); _arg1 = new CilVariable("__arg1", TargetModule.CorLibTypeFactory.UInt32); _result = new CilVariable("__result", TargetModule.CorLibTypeFactory.UInt32); }
private bool TryInferVariableType(CilVariable variable) { // Do not update the type of the flags variable. if (_context.FlagVariable == variable) { return(false); } var expectedTypes = variable.UsedBy .Select(use => use.IsReference // If ldloca/ldarga, get the underlying type of the expected byref type. ? ((ByReferenceTypeSignature)use.ExpectedType).BaseType : use.ExpectedType) .Where(t => t != null) #if DEBUG .ToArray() #endif ; var commonBaseType = _helper.GetCommonBaseType(expectedTypes); if (commonBaseType != null && variable.VariableType.FullName != commonBaseType.FullName) { var newType = _context.TargetImage.TypeSystem.GetMscorlibType(commonBaseType) ?? _context.ReferenceImporter.ImportTypeSignature(commonBaseType.ToTypeSignature()); variable.VariableType = newType; // Update the expression type of all references to the variable. foreach (var use in variable.UsedBy) { use.ExpressionType = use.IsReference ? new ByReferenceTypeSignature(newType) : newType; } // Update the expected type of all expressions that are assigned to the variable. foreach (var assign in variable.AssignedBy) { assign.Value.ExpectedType = newType; } return(true); } return(false); }
private ITypeDescriptor TryInferArrayType(CilVariable variable) { if (variable.AssignedBy.Count == 0) { return(null); } var types = variable.AssignedBy .Select(a => a.Value.ExpressionType) .ToArray(); if (types[0] is SzArrayTypeSignature arrayType && types.All(t => Comparer.Equals(t, arrayType))) { return(arrayType); } return(null); }
private ICollection <ITypeDescriptor> CollectExpectedTypes(CilVariable variable) { var expectedTypes = new List <ITypeDescriptor>(); foreach (var use in variable.UsedBy) { var expectedType = use.ExpectedType; if (expectedType == null) { continue; } if (!use.IsReference) { // Normal read reference to the variable (e.g. using a ldloc or ldarg). expectedTypes.Add(expectedType); } else if (expectedType is ByReferenceTypeSignature byRefType) { // The variable's address was used (e.g. using a ldloca or ldarga). To avoid the type inference // to think that the variable is supposed to be a byref type, we get the base type instead. expectedTypes.Add(byRefType.BaseType); } else { // If this happens, we probably have an error somewhere in an earlier stage of the recompiler. // Variable loaded by reference should always have a byref type sig as expected type. throw new RecompilerException( $"Variable {use.Variable.Name} in the expression `{use.Parent}` in " + $"{_context.MethodBody.Method.Name} ({_context.MethodBody.Method.MetadataToken}) was passed on " + $"by reference, but does not have a by-reference expected type."); } } return(expectedTypes); }
private bool TryInferVariableType(CilVariable variable) { // Do not update the type of the flags variable. if (_context.FlagVariable == variable) { return(false); } // Collect expected types. var expectedTypes = new List <ITypeDescriptor>(); foreach (var use in variable.UsedBy) { var expectedType = use.ExpectedType; if (!use.IsReference) { // Normal read reference to the variable (e.g. using a ldloc or ldarg). expectedTypes.Add(expectedType); } else if (expectedType is ByReferenceTypeSignature byRefType) { // The variable's address was used (e.g. using a ldloca or ldarga). To avoid the type inference // to think that the variable is supposed to be a byref type, we get the base type instead. expectedTypes.Add(byRefType.BaseType); } else { // If this happens, we probably have an error somewhere in an earlier stage of the recompiler. // Variable loaded by reference should always have a byref type sig as expected type. throw new RecompilerException( $"Variable {use.Variable.Name} in the expression `{use.Parent}` in " + $"{_context.MethodBody.Method.Name} ({_context.MethodBody.Method.MetadataToken}) was passed on " + $"by reference, but does not have a by-reference expected type."); } } var commonBaseType = _helper.GetCommonBaseType(expectedTypes); if (commonBaseType != null && variable.VariableType.FullName != commonBaseType.FullName) { var newType = _context.TargetImage.TypeSystem.GetMscorlibType(commonBaseType) ?? _context.ReferenceImporter.ImportTypeSignature(commonBaseType.ToTypeSignature()); variable.VariableType = newType; // Update the expression type of all references to the variable. foreach (var use in variable.UsedBy) { use.ExpressionType = use.IsReference ? new ByReferenceTypeSignature(newType) : newType; } // Update the expected type of all expressions that are assigned to the variable. foreach (var assign in variable.AssignedBy) { assign.Value.ExpectedType = newType; } return(true); } return(false); }