/// <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 != null)); if (body != null) { var seqPoint = body.Instructions.Select(i=>i.SequencePoint).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 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> /// Try to get a field with given reference in this type. /// The declaring type of the method reference is assumed to refer to this type. /// </summary> public bool TryGet(XFieldReference fieldRef, out XFieldDefinition field) { // Look in my own fields field = Fields.FirstOrDefault(x => x.IsSameExceptDeclaringType(fieldRef)); if (field != null) { return(true); } // Look in base type XTypeDefinition baseTypeDef; if ((BaseType != null) && BaseType.TryResolve(out baseTypeDef)) { return(baseTypeDef.TryGet(fieldRef, out field)); } return(false); }
/// <summary> /// Resolve this reference to it's definition. /// </summary> public virtual bool TryResolve(out XFieldDefinition field) { if (resolvedField != null) { field = resolvedField; return true; } field = null; XTypeDefinition declaringType; if (!DeclaringType.GetElementType().TryResolve(out declaringType)) return false; if (!declaringType.TryGet(this, out field)) return false; // Cache for later resolvedField = field; declaringType.AddFlushAction(() => resolvedField = null); return true; }
/// <summary> /// Resolve this reference to it's definition. /// </summary> public virtual bool TryResolve(out XFieldDefinition field) { if (resolvedField != null) { field = resolvedField; return(true); } field = null; XTypeDefinition declaringType; if (!DeclaringType.GetElementType().TryResolve(out declaringType)) { return(false); } if (!declaringType.TryGet(this, out field)) { return(false); } // Cache for later resolvedField = field; declaringType.AddFlushAction(() => resolvedField = null); return(true); }
/// <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> /// Record the given field mapping /// </summary> internal void Record(XFieldDefinition xField, DexLib.FieldDefinition dField) { xFieldMap.Add(xField, dField); }
/// <summary> /// Try to get the enum field that defines the given constant. /// </summary> public abstract bool TryGetEnumConstField(object value, out XFieldDefinition field);
/// <summary> /// Try to get a field with given reference in this type. /// The declaring type of the method reference is assumed to refer to this type. /// </summary> public bool TryGet(XFieldReference fieldRef, out XFieldDefinition field) { // Look in my own fields field = Fields.FirstOrDefault(x => x.IsSameExceptDeclaringType(fieldRef)); if (field != null) return true; // Look in base type XTypeDefinition baseTypeDef; if ((BaseType != null) && BaseType.TryResolve(out baseTypeDef)) { return baseTypeDef.TryGet(fieldRef, out field); } return false; }
/// <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()); }
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; }
/// <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> /// 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> /// 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; }