/// <summary> /// Is the given field initialized in the given code? /// </summary> private static bool IsInitialized(AstBlock ast, XFieldDefinition field) { var storeCode = field.IsStatic ? AstCode.Stsfld : AstCode.Stfld; var initExpressions = ast.GetSelfAndChildrenRecursive <AstExpression>(x => (x.Code == storeCode) && ((XFieldReference)x.Operand).IsSame(field)).ToList(); return(initExpressions.Any()); }
/// <summary> /// Record the given field mapping /// </summary> internal DexLib.FieldDefinition GetField(XFieldDefinition xField) { DexLib.FieldDefinition dfield; if (xFieldMap.TryGetValue(xField, out dfield)) { return(dfield); } throw new ArgumentException(string.Format("Field {0} not found", xField)); }
/// <summary> /// Create the current type as class definition. /// </summary> public virtual void Create(ClassDefinition declaringClass, XTypeDefinition declaringType, DexTargetPackage targetPackage) { // Find xfield xField = XBuilder.AsFieldDefinition(compiler.Module, field); // Create field definition dfield = new Dot42.DexLib.FieldDefinition(); dfield.Name = NameConverter.GetConvertedName(field); AddFieldToDeclaringClass(declaringClass, dfield, targetPackage); targetPackage.NameConverter.Record(xField, dfield); // Set access flags SetAccessFlags(dfield, field); // Give warning if static in generic class. // This could of cause also be handled automagically be the compiler, // with mixture of whats done in the Interlocked converter and whats // done in the GenericInstanceConverter. if (field.IsStatic && declaringType.IsGenericClass) { if (!field.HasSuppressMessageAttribute("StaticFieldInGenericType") && !field.DeclaringType.HasSuppressMessageAttribute("StaticFieldInGenericType")) { string msg; if (field.Name.Contains("CachedAnonymousMethodDelegate")) { msg = "The compiler generated a static field '{0}' in generic type '{1}'. This is not supported " + "in Dot42 if the anonymous delegate accesses a generic class parameter. A workaround " + "is to convert the anonymous static delegate to a normal method.\n"; } else { msg = "Static field '{0}' in generic type {1}: All generic instances will share " + "the same static field, contrary on how CLR operates. A workaround is to " + "use ConcurrentDictionaries to access the values dependent on the type.\n"; } msg += "You can suppress this warning with a [SuppressMessage(\"dot42\"," + " \"StaticFieldInGenericType\")] attribute, either on the field or on the class."; var body = field.DeclaringType.Methods.Select(m => m.Body) .FirstOrDefault(m => m != null && m.Instructions.Any(i => i.SequencePoint(m) != null)); if (body != null) { var seqPoint = body.Instructions.Select(i => i.SequencePoint(body)).First(i => i != null); DLog.Warning(DContext.CompilerILConverter, seqPoint.Document.Url, seqPoint.StartColumn, seqPoint.StartLine, msg, field.Name, declaringType.FullName); } else { DLog.Warning(DContext.CompilerILConverter, msg, field.Name, declaringType.FullName); } } } }
/// <summary> /// Create the body of the values() method. /// </summary> private AstBlock CreateValuesBody(XFieldDefinition enumInfoField, XTypeSystem typeSystem) { var internalEnumInfoType = Compiler.GetDot42InternalType("EnumInfo"); var valuesMethod = new XMethodReference.Simple("Values", true, typeSystem.Object, internalEnumInfoType); var ast = AstBlock.CreateOptimizedForTarget( new AstExpression(AstNode.NoSource, AstCode.Ret, null, new AstExpression(AstNode.NoSource, AstCode.SimpleCastclass, new XArrayType(XType), new AstExpression(AstNode.NoSource, AstCode.Call, valuesMethod, new AstExpression(AstNode.NoSource, AstCode.Ldsfld, enumInfoField))))); return(ast); }
/// <summary> /// Create the current type as class definition. /// </summary> public void Create(ClassDefinition declaringClass, DexTargetPackage targetPackage) { // Find xField xField = XBuilder.AsFieldDefinition(compiler.Module, field); // Create field definition dfield = new Dot42.DexLib.FieldDefinition(); dfield.Name = NameConverter.GetConvertedName(field); AddFieldToDeclaringClass(declaringClass, dfield, targetPackage); targetPackage.NameConverter.Record(xField, dfield); // Set access flags SetAccessFlags(dfield, field); }
/// <summary> /// Resolve this reference to it's definition. /// </summary> public override bool TryResolve(out XFieldDefinition field) { string fieldName; string descriptor; string className; if (TryGetJavaImportNames(out fieldName, out descriptor, out className)) { // Resolve to java field definition var declaringType = Java.XBuilder.AsTypeReference(Module, className, XTypeUsageFlags.DeclaringType); var fieldRef = Java.XBuilder.AsFieldReference(Module, fieldName, descriptor, declaringType, className); return fieldRef.TryResolve(out field); } field = this; return true; }
/// <summary> /// Resolve this reference to it's definition. /// </summary> public override bool TryResolve(out XFieldDefinition field) { string fieldName; string descriptor; string className; if (TryGetJavaImportNames(out fieldName, out descriptor, out className)) { // Resolve to java field definition var declaringType = Java.XBuilder.AsTypeReference(Module, className, XTypeUsageFlags.DeclaringType); var fieldRef = Java.XBuilder.AsFieldReference(Module, fieldName, descriptor, declaringType, className); return(fieldRef.TryResolve(out field)); } field = this; return(true); }
/// <summary> /// Try to get the enum field that defines the given constant. /// </summary> public override bool TryGetEnumConstField(object value, out XFieldDefinition field) { field = null; if (!type.IsEnum || (value == null)) { return(false); } var valueType = value.GetType(); var ilField = type.Fields.FirstOrDefault(x => x.IsStatic && Equals(XConvert.ChangeType(x.Constant, valueType), value)); if (ilField == null) { return(false); } field = Fields.OfType <ILFieldDefinition>().FirstOrDefault(x => x.OriginalField == ilField); return(field != null); }
/// <summary> /// Create the body of the valueOf(string) method. /// </summary> private AstBlock CreateValueOfBody(XSyntheticMethodDefinition method, XFieldDefinition enumInfoField, XTypeSystem typeSystem) { var internalEnumType = Compiler.GetDot42InternalType("Enum"); var internalEnumInfoType = Compiler.GetDot42InternalType("EnumInfo"); var parseMethod = new XMethodReference.Simple("Parse", true, internalEnumType, internalEnumInfoType, XParameter.Create("value", typeSystem.String), XParameter.Create("ignoreCase", typeSystem.Bool), XParameter.Create("throwIfNotFound", typeSystem.Bool)); var ast = AstBlock.CreateOptimizedForTarget( new AstExpression(AstNode.NoSource, AstCode.Ret, null, new AstExpression(AstNode.NoSource, AstCode.SimpleCastclass, XType, new AstExpression(AstNode.NoSource, AstCode.Call, parseMethod, new AstExpression(AstNode.NoSource, AstCode.Ldsfld, enumInfoField), new AstExpression(AstNode.NoSource, AstCode.Ldloc, method.AstParameters[0]), new AstExpression(AstNode.NoSource, AstCode.Ldc_I4, 0), new AstExpression(AstNode.NoSource, AstCode.Ldc_I4, 1))))); return(ast); }
/// <summary> /// Generate a iget opcode. /// </summary> internal static RCode IGet(this XFieldDefinition field) { var type = field.FieldType; if (type.IsDexWide()) { return(RCode.Iget_wide); } if (type.IsVoid()) { throw new ArgumentException("Unexpected void expression type"); } if (type.IsDexBoolean()) { return(RCode.Iget_boolean); } if (type.IsDexChar()) { return(RCode.Iget_char); } if (type.IsDexShort()) { return(RCode.Iget_short); } if (type.IsDexByte()) { return(RCode.Iget_byte); } if (type.IsDexValue()) { return(RCode.Iget); } if (type.IsDexObject()) { return(RCode.Iget_object); } throw new ArgumentException("Unknown type in iget " + type); }
/// <summary> /// Try to get the enum field that defines the given constant. /// </summary> public override bool TryGetEnumConstField(object value, out XFieldDefinition field) { field = null; return false; }
/// <summary> /// Try to get the enum field that defines the given constant. /// </summary> public override bool TryGetEnumConstField(object value, out XFieldDefinition field) { field = null; return(false); }
/// <summary> /// Generate a iput opcode. /// </summary> internal static RCode IPut(this XFieldDefinition field) { var type = field.FieldType; return(type.IPut()); }
/// <summary> /// Record the given field mapping /// </summary> internal void Record(XFieldDefinition xField, DexLib.FieldDefinition dField) { xFieldMap.Add(xField, dField); }
/// <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); }
/// <summary> /// Try to get the enum field that defines the given constant. /// </summary> public override bool TryGetEnumConstField(object value, out XFieldDefinition field) { field = null; if (!type.IsEnum || (value == null)) return false; var valueType = value.GetType(); var ilField = type.Fields.FirstOrDefault(x => x.IsStatic && Equals(XConvert.ChangeType(x.Constant, valueType), value)); if (ilField == null) return false; field = Fields.OfType<ILFieldDefinition>().FirstOrDefault(x => x.OriginalField == ilField); return (field != null); }
private static bool InterlockedUsingUpdater(AstExpression interlockedCall, string methodName, XFieldReference field, XFieldDefinition updater, AstExpression targetExpr, AstExpression parentExpr, AssemblyCompiler compiler) { bool isStatic = field.Resolve().IsStatic; string replacementMethod = null; if (methodName == "Increment") { replacementMethod = "IncrementAndGet"; } else if (methodName == "Decrement") { replacementMethod = "DecrementAndGet"; } else if (methodName == "Add") { replacementMethod = "AddAndGet"; } else if (methodName == "Read") { replacementMethod = "Get"; } else if (methodName.StartsWith("Exchange")) { replacementMethod = "GetAndSet"; } else if (methodName.StartsWith("CompareAndSet")) { // this patches through to the original java method for performance purists. replacementMethod = "CompareAndSet"; } else if (methodName.StartsWith("CompareExchange")) { if (TransformCompareExchangeToCompareAndSet(parentExpr, compiler, ref interlockedCall)) { replacementMethod = "CompareAndSet"; } else { // The semantics here are slighlty different. Java returns a 'true' on // success, while BCL returns the old value. We have crafted a replacement // method with the BCL semantics though. replacementMethod = "CompareExchange"; } } else { return(false); } var updaterType = updater.FieldType.Resolve(); var methodRef = updaterType.Methods.FirstOrDefault(f => f.Name == replacementMethod); if (methodRef == null && methodName == "CompareExchange") { methodRef = updaterType.Methods.FirstOrDefault(f => f.Name.StartsWith(replacementMethod)); } if (methodRef == null) { return(false); } interlockedCall.Operand = methodRef; if (isStatic) { interlockedCall.Arguments[0] = new AstExpression(interlockedCall.SourceLocation, AstCode.Ldnull, null) .SetType(field.DeclaringType); } else { interlockedCall.Arguments[0] = targetExpr.Arguments[0]; } // add field updater instance argument. var ldUpdater = new AstExpression(interlockedCall.SourceLocation, AstCode.Ldsfld, updater) .SetType(updaterType); interlockedCall.Arguments.Insert(0, ldUpdater); return(true); }