/// <summary> /// Try to resolve definition from reference. /// </summary> internal static PropertyDefinition Resolve(this PropertyReference prop, ReachableContext context) { var declType = prop.DeclaringType.Resolve(context); var resolver = new GenericsResolver(declType); return((declType == null) ? null : declType.Properties.FirstOrDefault(x => x.AreSame(prop, resolver.Resolve))); }
/// <summary> /// Try to resolve definition from reference. /// </summary> internal static EventDefinition Resolve(this EventReference evt, ReachableContext context) { var declType = evt.DeclaringType.Resolve(context); var resolver = new GenericsResolver(declType); return((declType == null) ? null : declType.Events.FirstOrDefault(x => x.AreSame(evt, resolver.Resolve))); }
/// <summary> /// The given type has been made reachable. /// </summary> internal void IncludeIfNeeded(ReachableContext context) { if ((typeCondition == null) || (typeCondition.IsReachable)) { member.MarkReachable(context); } }
/// <summary> /// Implement IAsyncSetThis. /// </summary> private static void ImplementISetThis(TypeDefinition type, ReachableContext reachableContext) { var thisField = type.Fields.FirstOrDefault(x => x.Name.StartsWith("<>") && x.Name.EndsWith("__this")); if (thisField == null) { return; } // Add interface var intfType = type.Module.Import(new TypeReference(InternalConstants.Dot42InternalNamespace, "IAsyncSetThis", type.Module, type.Module.Assembly.Name)); type.Interfaces.Add(new InterfaceImpl(intfType)); // Add "SetThis(object)" method var method = new MethodDefinition("SetThis", MethodAttributes.Public, type.Module.TypeSystem.Void); method.SetReachable(reachableContext); type.Methods.Add(method); var valueParam = new ParameterDefinition(type.Module.TypeSystem.Object); method.Parameters.Add(valueParam); method.Body = new MethodBody(method) { InitLocals = true }; var seq = new ILSequence(); seq.Emit(OpCodes.Ldarg_0); // this seq.Emit(OpCodes.Ldarg, valueParam); seq.Emit(OpCodes.Castclass, thisField.FieldType); seq.Emit(OpCodes.Stfld, thisField); seq.Emit(OpCodes.Ret); seq.AppendTo(method.Body); }
/// <summary> /// Try to resolve definition from reference. /// </summary> internal static MethodDefinition Resolve(this MethodReference method, ReachableContext context) { var declType = method.DeclaringType.Resolve(context); var resolver = new GenericsResolver(declType); return((declType == null) ? null : declType.Methods.FirstOrDefault(x => x.AreSame(method, resolver.Resolve))); }
/// <summary> /// Walk the given member. /// </summary> internal static void Walk(ReachableContext context, AbstractReference member) { if (member == null) return; ClassFile classFile; FieldDefinition field; MethodDefinition method; TypeReference typeRef; if ((classFile = member as ClassFile) != null) { Walk(context, classFile); } else if ((method = member as MethodDefinition) != null) { Walk(context, method); } else if ((field = member as FieldDefinition) != null) { Walk(context, field); } else if ((typeRef = member as TypeReference) != null) { Walk(context, typeRef); } }
/// <summary> /// Create the Ctor /// </summary> private static void CreateDefaultCtor(ReachableContext reachableContext, TypeDefinition type) { var typeSystem = type.Module.TypeSystem; var ctor = new MethodDefinition(".ctor", MethodAttributes.Public | MethodAttributes.SpecialName | MethodAttributes.RTSpecialName, typeSystem.Void); ctor.DeclaringType = type; var body = new MethodBody(ctor); body.InitLocals = true; ctor.Body = body; // Prepare code var seq = new ILSequence(); seq.Emit(OpCodes.Nop); seq.Emit(OpCodes.Ret); // Append ret sequence seq.AppendTo(body); // Update offsets body.ComputeOffsets(); // Add ctor type.Methods.Add(ctor); ctor.SetReachable(reachableContext); }
/// <summary> /// Mark all eachable items in argument as such. /// </summary> private static void Walk(ReachableContext context, IGenericParameterProvider provider) { if (provider.HasGenericParameters) { // Include types needed for generics GetDot42InternalType(context, InternalConstants.TypeHelperName).MarkReachable(context); var providerAsType = provider as TypeDefinition; if ((providerAsType != null) && !providerAsType.IsStatic()) { GetDot42InternalType(context, InternalConstants.TypeReflectionInfoAnnotation).MarkReachable(context); GetDot42InternalType(context, InternalConstants.GenericTypeParameterAnnotation).MarkReachable(context); GetDot42InternalType(context, InternalConstants.GenericDefinitionAnnotation).MarkReachable(context); } if (provider is MethodDefinition) { GetDot42InternalType(context, InternalConstants.GenericMethodParameterAnnotation).MarkReachable(context); GetDot42InternalType(context, InternalConstants.GenericDefinitionAnnotation).MarkReachable(context); } // Mark parameters foreach (GenericParameter param in provider.GenericParameters) { param.MarkReachable(context); } } }
/// <summary> /// Implement IAsyncSetThis. /// </summary> private static void ImplementISetThis(TypeDefinition type, ReachableContext reachableContext) { var thisField = type.Fields.FirstOrDefault(x => x.Name.StartsWith("<>") && x.Name.EndsWith("__this")); if (thisField == null) return; // Add interface var intfType = type.Module.Import(new TypeReference(InternalConstants.Dot42InternalNamespace, "IAsyncSetThis", type.Module, type.Module.Assembly.Name)); type.Interfaces.Add(new InterfaceImpl(intfType)); // Add "SetThis(object)" method var method = new MethodDefinition("SetThis", MethodAttributes.Public, type.Module.TypeSystem.Void); method.SetReachable(reachableContext); type.Methods.Add(method); var valueParam = new ParameterDefinition(type.Module.TypeSystem.Object); method.Parameters.Add(valueParam); method.Body = new MethodBody(method) { InitLocals = true }; var seq = new ILSequence(); seq.Emit(OpCodes.Ldarg_0); // this seq.Emit(OpCodes.Ldarg, valueParam); seq.Emit(OpCodes.Castclass, thisField.FieldType); seq.Emit(OpCodes.Stfld, thisField); seq.Emit(OpCodes.Ret); seq.AppendTo(method.Body); }
/// <summary> /// Mark all base types and externally visible members reachable /// </summary> private static void Walk(ReachableContext context, TypeReference type) { if (type == null) { return; } if (type.IsArray) { var aType = (ArrayTypeReference)type; Walk(context, aType.ElementType); } else if (type.IsObjectType) { var oType = (ObjectTypeReference)type; foreach (var typeArg in oType.Arguments) { Walk(context, typeArg.Signature); } ClassFile classFile; if (context.TryLoadClass(oType.ClassName, out classFile)) { classFile.MarkReachable(context); } } else if (type.IsBaseType || type.IsVoid || type.IsTypeVariable) { // Not need to mark anything } else { throw new ArgumentException("Unknown type: " + type); } }
/// <summary> /// The given type has been made reachable. /// </summary> /// <returns>True if the type was marked reachable, false otherwise</returns> public bool IncludeIfNeeded(ReachableContext context, TypeDefinition type, TypeDefinition dot42IncludeType) { if (_pattern == null) return false; return ApplyByPattern.Apply(_pattern, type, member => Include(member, context, dot42IncludeType)); }
/// <summary> /// Walk the given member. /// </summary> internal static void Walk(ReachableContext context, AbstractReference member) { if (member == null) { return; } ClassFile classFile; FieldDefinition field; MethodDefinition method; TypeReference typeRef; if ((classFile = member as ClassFile) != null) { Walk(context, classFile); } else if ((method = member as MethodDefinition) != null) { Walk(context, method); } else if ((field = member as FieldDefinition) != null) { Walk(context, field); } else if ((typeRef = member as TypeReference) != null) { Walk(context, typeRef); } }
/// <summary> /// The given type has been made reachable. /// </summary> /// <returns>True if the type was marked reachable, false otherwise</returns> internal bool IncludeIfNeeded(ReachableContext context, TypeDefinition type) { if (type.IsReachable) return true; // Already included if (instanceOfCondition.IsInterface) { // Check implements if (Implements(context, type)) { type.MarkReachable(context); return true; } } else { // Check extends if (Extends(context, type)) { type.MarkReachable(context); return true; } } return false; }
/// <summary> /// The given type has been made reachable. /// </summary> /// <returns>True if the class was marked reachable, false otherwise</returns> internal bool IncludeIfNeeded(ReachableContext context, ClassFile javaClass) { if (javaClass.IsReachable) return true; // Already included if (className == null) return false; if (instanceOfCondition.IsInterface) { // Check implements if (Implements(context, javaClass)) { javaClass.MarkReachable(context); return true; } } else { // Check extends if (Extends(javaClass)) { javaClass.MarkReachable(context); return true; } } return false; }
/// <summary> /// Mark all properties with the given name reachable. /// </summary> internal static void MarkPropertiesReachable(this TypeReference type, string propertyName, ReachableContext context) { while ((type != null) && (context.Contains(type))) { TypeDefinition typeDef = context.GetTypeDefinition(type); if (typeDef != null) { if (typeDef.HasProperties) { foreach (PropertyDefinition prop in typeDef.Properties) { if (prop.Name == propertyName) { prop.MarkReachable(context); } } } type = typeDef.BaseType; } else { type = null; } } }
/// <summary> /// Implement IAsyncSetThis where needed. /// </summary> public void Convert(ReachableContext reachableContext) { foreach (var type in reachableContext.ReachableTypes.Where(IsAsyncStateMachine)) { ImplementISetThis(type, reachableContext); } }
/// <summary> /// Mark all eachable items in argument as such. /// </summary> private static void Walk(ReachableContext context, ClassFile classFile) { // Mark owner classFile.DeclaringClass.MarkReachable(context); // Mark base class classFile.SuperClass.MarkReachable(context); // Mark interfaces if (classFile.Interfaces != null) { foreach (var intf in classFile.Interfaces) { intf.MarkReachable(context); } } // Mark class ctor classFile.Methods.FirstOrDefault(x => x.Name == "<clinit>").MarkReachable(context); // Mark methods of imported classes reachable if (classFile.IsCreatedByLoader) { classFile.Methods.Where(x => x.IsPublic || x.IsProtected).ForEach(x => x.MarkReachable(context)); } // If this is a class that does not have an imported C# wrapper, be safe and include everything from this class. if (!context.HasDexImport(classFile)) { context.MarkAsRoot(classFile); } // Record in context context.RecordReachableType(classFile); }
/// <summary> /// Make sure all struct fields are initialized in the ctors that need them. /// </summary> private static void InitializeStructFields(ReachableContext reachableContext, TypeDefinition type, List <FieldDefinition> structFields) { List <Tuple <MethodDefinition, HashSet <FieldDefinition> > > ctorsToExtend = null; foreach (var ctor in type.Methods.Where(x => x.IsConstructor && !x.IsStatic && x.HasBody)) { HashSet <FieldDefinition> storedFields; if (!NeedsStructInitialization(ctor, structFields, out storedFields)) { continue; } // Extend this ctor to initialize all struct fields. if (ctorsToExtend == null) { ctorsToExtend = new List <Tuple <MethodDefinition, HashSet <FieldDefinition> > >(); } ctorsToExtend.Add(Tuple.Create(ctor, storedFields)); } if (ctorsToExtend == null) { // No ctors need additional initialization return; } // Inject initialization code foreach (var tuple in ctorsToExtend) { var ctor = tuple.Item1; var storedFields = tuple.Item2; InjectInitializationCode(ctor, structFields.Except(storedFields)); } }
/// <summary> /// Add bridge methods when a method with a non-generic parameter overrides a method with a generic parameter. /// </summary> public void Convert(ReachableContext reachableContext) { this.reachableContext = reachableContext; // Initialize some sets reachableMethods = reachableContext.ReachableTypes.Where(x => !x.HasDexImportAttribute()) .SelectMany(x => x.Methods) .Where(m => m.IsReachable) .ToList(); // Do we need to convert anything? foreach (var method in reachableMethods) { MethodDefinition baseMethod; if (!NeedsBridge(method, out baseMethod)) continue; // Add bridge var bridge = AddBridge(method, baseMethod); // Remove bridge if is has an exact duplicate var duplicate = method.DeclaringType.Methods.FirstOrDefault(x => (x != bridge) && x.AreSame(bridge, null)); if (duplicate != null) { bridge.DeclaringType.Methods.Remove(bridge); } } }
/// <summary> /// Ensure there is a class ctor. /// </summary> private static MethodDefinition EnsureClassCtor(ReachableContext reachableContext, TypeDefinition type) { var ctor = type.GetClassCtor(); if (ctor != null) return ctor; // Already exists // Create class ctor var typeSystem = type.Module.TypeSystem; ctor = new MethodDefinition(".cctor", MethodAttributes.Public | MethodAttributes.SpecialName | MethodAttributes.RTSpecialName | MethodAttributes.Static | MethodAttributes.SpecialName, typeSystem.Void); ctor.DeclaringType = type; var body = new MethodBody(ctor); body.InitLocals = true; ctor.Body = body; // Prepare code var seq = new ILSequence(); seq.Emit(OpCodes.Nop); seq.Emit(OpCodes.Ret); // Append ret sequence seq.AppendTo(body); // Update offsets body.ComputeOffsets(); // Add ctor type.Methods.Add(ctor); ctor.SetReachable(reachableContext); return ctor; }
/// <summary> /// Mark all eachable items in argument as such. /// </summary> private static void Walk(ReachableContext context, PropertyReference prop) { prop.PropertyType.MarkReachable(context); // Parameters if (prop.Parameters.Count > 0) { foreach (ParameterDefinition param in prop.Parameters) { Walk(context, (ParameterReference)param); } } var propDef = prop as PropertyDefinition; if (propDef != null) { // DO NOT AUTOMATICALLY MAKE GET and SET REACHABLE. //propDef.GetMethod.MarkReachable(context); //propDef.SetMethod.MarkReachable(context); // Custom attributes Walk(context, (ICustomAttributeProvider)propDef); } else { // Try to resolve prop.Resolve(context).MarkReachable(context); } }
/// <summary> /// Mark all children of the given member /// </summary> internal static void Walk(ReachableContext context, MemberReference member) { // Mark declaring type member.DeclaringType.MarkReachable(context); TypeReference typeRef; MethodReference methodRef; EventReference eventRef; FieldReference fieldRef; PropertyReference propertyRef; if ((typeRef = member as TypeReference) != null) { Walk(context, typeRef); } else if ((methodRef = member as MethodReference) != null) { Walk(context, methodRef); } else if ((eventRef = member as EventReference) != null) { Walk(context, eventRef); } else if ((fieldRef = member as FieldReference) != null) { Walk(context, fieldRef); } else if ((propertyRef = member as PropertyReference) != null) { Walk(context, propertyRef); } }
/// <summary> /// Mark all eachable items in argument as such. /// </summary> private static void Walk(ReachableContext context, FieldReference field) { // Field type field.FieldType.MarkReachable(context); var fieldDef = field as FieldDefinition; if (fieldDef != null) { // Custom attributes Walk(context, (ICustomAttributeProvider)fieldDef); // Walk imported java classes CustomAttribute javaImportAttr; if ((javaImportAttr = fieldDef.GetJavaImportAttribute()) != null) { string className; string memberName; string descriptor; javaImportAttr.GetDexOrJavaImportNames(fieldDef, out memberName, out descriptor, out className); ClassFile javaClass; if (context.TryLoadClass(className, out javaClass)) { var javaField = javaClass.Fields.FirstOrDefault(x => (x.Name == memberName) && (x.Descriptor == descriptor)); javaClass.MarkReachable(context); javaField.MarkReachable(context); } } } else { // Try to resolve field.Resolve(context).MarkReachable(context); } }
/// <summary> /// Create static ctors for types that have reachable static enum and/or struct fields. /// </summary> public void Convert(ReachableContext reachableContext) { foreach (var type in reachableContext.ReachableTypes.Where(NeedsClassCtor)) { EnsureClassCtor(reachableContext, type); } }
/// <summary> /// Make sure all struct fields are initialized in the ctors that need them. /// </summary> private static void InitializeStructFields(ReachableContext reachableContext, TypeDefinition type, List<FieldDefinition> structFields) { List<Tuple<MethodDefinition, HashSet<FieldDefinition>>> ctorsToExtend = null; foreach (var ctor in type.Methods.Where(x => x.IsConstructor && !x.IsStatic && x.HasBody)) { HashSet<FieldDefinition> storedFields; if (!NeedsStructInitialization(ctor, structFields, out storedFields)) continue; // Extend this ctor to initialize all struct fields. if (ctorsToExtend == null) ctorsToExtend = new List<Tuple<MethodDefinition, HashSet<FieldDefinition>>>(); ctorsToExtend.Add(Tuple.Create(ctor, storedFields)); } if (ctorsToExtend == null) { // No ctors need additional initialization return; } // Inject initialization code foreach (var tuple in ctorsToExtend) { var ctor = tuple.Item1; var storedFields = tuple.Item2; InjectInitializationCode(ctor, structFields.Except(storedFields)); } }
/// <summary> /// Add bridge methods when a method with a non-generic parameter overrides a method with a generic parameter. /// </summary> public void Convert(ReachableContext reachableContext) { this.reachableContext = reachableContext; // Initialize some sets reachableMethods = reachableContext.ReachableTypes.Where(x => !x.HasDexImportAttribute()).SelectMany(x => x.Methods).Where(m => m.IsReachable).OrderBy(x => x.FullName).ToList(); // Do we need to convert anything? foreach (var method in reachableMethods) { MethodDefinition baseMethod; if (!NeedsBridge(method, out baseMethod)) { continue; } // Add bridge var bridge = AddBridge(method, baseMethod); // Remove bridge if is has an exact duplicate var duplicate = method.DeclaringType.Methods.FirstOrDefault(x => (x != bridge) && x.AreSame(bridge, null)); if (duplicate != null) { bridge.DeclaringType.Methods.Remove(bridge); } } }
/// <summary> /// Mark all base types and externally visible members reachable /// </summary> private static void Walk(ReachableContext context, TypeReference type) { if (type == null) return; if (type.IsArray) { var aType = (ArrayTypeReference)type; Walk(context, aType.ElementType); } else if (type.IsObjectType) { var oType = (ObjectTypeReference)type; foreach (var typeArg in oType.Arguments) { Walk(context, typeArg.Signature); } ClassFile classFile; if (context.TryLoadClass(oType.ClassName, out classFile)) { classFile.MarkReachable(context); } } else if (type.IsBaseType || type.IsVoid || type.IsTypeVariable) { // Not need to mark anything } else { throw new ArgumentException("Unknown type: " + type); } }
/// <summary> /// Mark all eachable items in argument as such. /// </summary> private static void Walk(ReachableContext context, MethodDefinition method) { method.DeclaringClass.MarkReachable(context); method.ReturnType.MarkReachable(context); // All parameters foreach (var param in method.Parameters) { param.MarkReachable(context); } // Base methods if (!method.IsStatic && !method.IsFinal) { MethodDefinition baseMethod; if ((baseMethod = method.GetBaseMethod()) != null) { if (context.Contains(baseMethod.DeclaringClass)) { baseMethod.MarkReachable(context); } } } Walk(context, method.Body); }
/// <summary> /// Create a type builder for the given type. /// </summary> internal static IClassBuilder[] Create(ReachableContext context, AssemblyCompiler compiler, TypeDefinition typeDef) { if (typeDef.FullName == "<Module>") return new IClassBuilder[] { new SkipClassBuilder() }; if (typeDef.IsDelegate()) return new IClassBuilder[] {new DelegateClassBuilder(context, compiler, typeDef) }; if (typeDef.IsAttribute()) return new IClassBuilder[] {new AttributeClassBuilder(context, compiler, typeDef) }; if (typeDef.IsAnnotation()) return new IClassBuilder[] {new AnnotationClassBuilder(context, compiler, typeDef) }; if (typeDef.HasDexImportAttribute()) return new IClassBuilder[] {new DexImportClassBuilder(context, compiler, typeDef) }; if (typeDef.HasJavaImportAttribute()) return new IClassBuilder[] {CreateJavaImportBuilder(context, compiler, typeDef)}; if (typeDef.IsEnum) { if (typeDef.UsedInNullableT) { var nullableBaseClassBuilder = new NullableEnumBaseClassBuilder(context, compiler, typeDef); IClassBuilder builder = new EnumClassBuilder(context, compiler, typeDef, nullableBaseClassBuilder); return new[] { builder, nullableBaseClassBuilder }; } return new IClassBuilder[] { new EnumClassBuilder(context, compiler, typeDef, null) }; } else { IClassBuilder builder = new StandardClassBuilder(context, compiler, typeDef); if (typeDef.UsedInNullableT) return new[] { builder, new NullableBaseClassBuilder(context, compiler, typeDef) }; return new[] { builder }; } }
/// <summary> /// Mark all eachable items in argument as such. /// </summary> private static void Walk(ReachableContext context, CodeAttribute code) { if (code == null) { return; } // Exception handlers foreach (var handler in code.ExceptionHandlers) { handler.CatchType.MarkReachable(context); } // Local variables /*foreach (var var in code.Variables) * { * var.VariableType.MarkReachable(context); * }*/ // Instructions foreach (var ins in code.Instructions) { object operand = ins.Operand; if (operand != null) { ConstantPoolClass cpClass; ConstantPoolFieldRef cpField; ConstantPoolMethodRef cpMethod; if ((cpClass = operand as ConstantPoolClass) != null) { ClassFile cf; if (cpClass.TryResolve(out cf)) { cf.MarkReachable(context); } } else if ((cpField = operand as ConstantPoolFieldRef) != null) { FieldDefinition fieldDef; if (cpField.TryResolve(out fieldDef)) { fieldDef.MarkReachable(context); } } else if ((cpMethod = operand as ConstantPoolMethodRef) != null) { MethodDefinition method; if (cpMethod.TryResolve(out method)) { method.MarkReachable(context); } else { } } } } }
/// <summary> /// Mark all fields with the given name reachable. /// </summary> internal static void MarkFieldsReachable(this TypeReference type, string fieldName, ReachableContext context) { while ((type != null) && (context.Contains(type))) { TypeDefinition typeDef = context.GetTypeDefinition(type); if (typeDef != null) { if (typeDef.HasFields) { foreach (FieldDefinition field in typeDef.Fields) { if (field.Name == fieldName) { field.MarkReachable(context); } } } type = typeDef.BaseType; } else { type = null; } } }
/// <summary> /// Create a CopyFrom method. /// </summary> private static MethodDefinition CreateCopyFromMethod(ReachableContext reachableContext, TypeDefinition type) { var typeSystem = type.Module.TypeSystem; var method = new MethodDefinition(NameConstants.Struct.CopyFromMethodName, MethodAttributes.Public, type); var sourceParam = new ParameterDefinition(type); method.Parameters.Add(sourceParam); method.DeclaringType = type; var body = new MethodBody(method); body.InitLocals = true; method.Body = body; // Prepare code var seq = new ILSequence(); seq.Emit(OpCodes.Nop); // Call base CopyFrom var baseType = (type.BaseType != null) ? type.BaseType.GetElementType().Resolve() : null; if ((baseType != null) && baseType.IsValueType && (baseType.FullName != "System.ValueType")) { var baseMethod = new MethodReference(NameConstants.Struct.CopyFromMethodName, baseType, baseType) { HasThis = true }; baseMethod.Parameters.Add(new ParameterDefinition(baseType)); seq.Emit(OpCodes.Ldarg, sourceParam); seq.Emit(OpCodes.Call, baseMethod); } // Copy all fields foreach (var field in type.Fields.Where(x => !x.IsStatic)) { // Not need to bother with cloning struct-type fields here, // as this will be done automatically by one of the Converters. // Prepare for stfld seq.Emit(OpCodes.Ldarg, body.ThisParameter); // Load from source seq.Emit(OpCodes.Ldarg, sourceParam); seq.Emit(OpCodes.Ldfld, field); // Save in this seq.Emit(OpCodes.Stfld, field); } // Return this seq.Emit(OpCodes.Ldarg, body.ThisParameter); seq.Emit(OpCodes.Ret); // Append ret sequence seq.AppendTo(body); // Update offsets body.ComputeOffsets(); // Add method type.Methods.Add(method); method.SetReachable(reachableContext); return method; }
/// <summary> /// Convert all constructs of IL that are not compatible with java. /// </summary> internal static void Convert(ReachableContext reachableContext) { foreach (var factory in ConverterFactories) { var converter = factory.Create(); converter.Convert(reachableContext); } }
/// <summary> /// Mark all children of the given assembly /// </summary> internal static void Walk(ReachableContext context, AssemblyDefinition assembly) { Walk(context, (ICustomAttributeProvider)assembly); foreach (ModuleDefinition mod in assembly.Modules) { Walk(context, (ICustomAttributeProvider)mod); } }
private void CreateDefaultField(ReachableContext reachableContext, TypeDefinition type) { // create the field var field = new FieldDefinition(NameConstants.Struct.DefaultFieldName, FieldAttributes.InitOnly | FieldAttributes.Static | FieldAttributes.Public, type); type.Fields.Add(field); field.SetReachable(reachableContext, true); }
/// <summary> /// Create static ctors for types that have dllimport methods. /// </summary> public void Convert(ReachableContext reachableContext) { foreach (var type in reachableContext.ReachableTypes.Where(NeedsClassCtor)) { var classCtor = EnsureClassCtor(reachableContext, type); AddLoadLibraryCalls(type, classCtor); } }
/// <summary> /// Mark all children of the given assembly /// </summary> internal static void Walk(ReachableContext context, AssemblyDefinition assembly) { Walk(context, (ICustomAttributeProvider) assembly); foreach (ModuleDefinition mod in assembly.Modules) { Walk(context, (ICustomAttributeProvider) mod); } }
/// <summary> /// Should the given method be included in the APK? /// </summary> public bool Include(MethodDefinition method, ReachableContext context) { if (!(method.HasNUnitTestAttribute() && method.DeclaringType.HasNUnitTestFixtureAttribute())) return false; // Include the NUnit base class var xType = context.Compiler.GetDot42InternalType("Dot42.Test", "NUnitTestCase").Resolve(); ((TypeDefinition)xType.OriginalTypeDefinition).MarkReachable(context); return true; }
/// <summary> /// Create static ctors for types that have dllimport methods. /// </summary> public void Convert(ReachableContext reachableContext) { var rechableMethods = reachableContext.ReachableTypes.SelectMany(r=>r.Methods) .Where(m=> m.IsReachable && m.HasBody); foreach (var method in rechableMethods) { FixAccesses(method.Body); } }
/// <summary> /// Create a type builder for the given type with JavaImport attribute. /// </summary> internal static IClassBuilder CreateJavaImportBuilder(ReachableContext context, AssemblyCompiler compiler, TypeDefinition typeDef) { var javaImportAttr = typeDef.GetJavaImportAttribute(true); var className = (string)javaImportAttr.ConstructorArguments[0].Value; ClassFile classFile; if (!compiler.ClassLoader.TryLoadClass(className, out classFile)) throw new ClassNotFoundException(className); context.RecordReachableType(classFile); return new SkipClassBuilder(); }
/// <summary> /// Mark all eachable items in argument as such. /// </summary> private static void Walk(ReachableContext context, IGenericInstance instance) { if (instance.HasGenericArguments) { foreach (TypeReference typeRef in instance.GenericArguments) { typeRef.MarkReachable(context); } } }
/// <summary> /// Should the given method be included in the APK? /// </summary> public bool Include(MethodDefinition method, ReachableContext context) { if (!method.IsVirtual) return false; if (method.GetDexImportBaseMethod() != null) return true; if (method.GetDexImportBaseInterfaceMethod() != null) return true; return false; }
/// <summary> /// Create static ctors for types that have dllimport methods. /// </summary> public void Convert(ReachableContext reachableContext) { var rechableMethods = reachableContext.ReachableTypes.SelectMany(r => r.Methods) .Where(m => m.IsReachable && m.HasBody); foreach (var method in rechableMethods) { FixAccesses(method.Body); } }
/// <summary> /// Extend instance ctors for types that have reachable instance fields of type struct. /// </summary> public void Convert(ReachableContext reachableContext) { foreach (var type in reachableContext.ReachableTypes) { List<FieldDefinition> structFields; if (HasInstanceStructFields(type, out structFields)) { InitializeStructFields(reachableContext, type, structFields); } } }
/// <summary> /// Extend instance ctors for types that have reachable instance fields of type struct. /// </summary> public void Convert(ReachableContext reachableContext) { foreach (var type in reachableContext.ReachableTypes) { List <FieldDefinition> structFields; if (HasInstanceStructFields(type, out structFields)) { InitializeStructFields(reachableContext, type, structFields); } } }
/// <summary> /// Create a type builder for the given type. /// </summary> internal static IClassBuilder[] Create(ReachableContext context, AssemblyCompiler compiler, TypeDefinition typeDef) { if (typeDef.FullName == "<Module>") { return new IClassBuilder[] { new SkipClassBuilder() } } ; if (typeDef.IsDelegate()) { return new IClassBuilder[] { new DelegateClassBuilder(context, compiler, typeDef) } } ; if (typeDef.IsAttribute()) { return new IClassBuilder[] { new AttributeClassBuilder(context, compiler, typeDef) } } ; if (typeDef.IsAnnotation()) { return new IClassBuilder[] { new AnnotationClassBuilder(context, compiler, typeDef) } } ; if (typeDef.HasDexImportAttribute()) { return new IClassBuilder[] { new DexImportClassBuilder(context, compiler, typeDef) } } ; if (typeDef.HasJavaImportAttribute()) { return new IClassBuilder[] { CreateJavaImportBuilder(context, compiler, typeDef) } } ; if (typeDef.IsEnum) { if (typeDef.UsedInNullableT) { var nullableBaseClassBuilder = new NullableEnumBaseClassBuilder(context, compiler, typeDef); IClassBuilder builder = new EnumClassBuilder(context, compiler, typeDef, nullableBaseClassBuilder); return(new[] { builder, nullableBaseClassBuilder }); } return(new IClassBuilder[] { new EnumClassBuilder(context, compiler, typeDef, null) }); } else { IClassBuilder builder = new StandardClassBuilder(context, compiler, typeDef); if (typeDef.UsedInNullableT) { return new[] { builder, new NullableBaseClassBuilder(context, compiler, typeDef) } } ; return(new[] { builder }); } }
/// <summary> /// Create default ctors for reachable structs. /// </summary> public void Convert(ReachableContext reachableContext) { // Collect all type var todoTypes = reachableContext.ReachableTypes.Where(x => x.IsValueType && !x.IsPrimitive && !x.IsEnum & !HasDefaultCtor(x)).ToList(); if (todoTypes.Count == 0) return; foreach (var type in todoTypes) { CreateDefaultCtor(reachableContext, type); } }
/// <summary> /// Should the given method be included in the APK? /// </summary> public bool Include(MethodDefinition method, ReachableContext context) { if (!(method.HasNUnitTestAttribute() && method.DeclaringType.HasNUnitTestFixtureAttribute())) { return(false); } // Include the NUnit base class var xType = context.Compiler.GetDot42InternalType("Dot42.Test", "NUnitTestCase").Resolve(); ((TypeDefinition)xType.OriginalTypeDefinition).MarkReachable(context); return(true); }
/// <summary> /// Mark all eachable items in argument as such. /// </summary> private static void Walk(ReachableContext context, ICustomAttributeProvider provider) { if (provider.HasCustomAttributes) { foreach (var attr in provider.CustomAttributes) { if (!attr.AttributeType.Resolve().HasIgnoreAttribute()) { Walk(context, attr); } } } }
/// <summary> /// Create a type builder for the given type with JavaImport attribute. /// </summary> internal static IClassBuilder CreateJavaImportBuilder(ReachableContext context, AssemblyCompiler compiler, TypeDefinition typeDef) { var javaImportAttr = typeDef.GetJavaImportAttribute(true); var className = (string)javaImportAttr.ConstructorArguments[0].Value; ClassFile classFile; if (!compiler.ClassLoader.TryLoadClass(className, out classFile)) { throw new ClassNotFoundException(className); } context.RecordReachableType(classFile); return(new SkipClassBuilder()); }
/// <summary> /// Should the given member reference in the given instruction be excluded from being walked? /// </summary> private static bool ExcludeFromWalking(ReachableContext context, Instruction ins, MemberReference memberReference) { // Is the given member reference a reference to an array initializer field? MethodReference method; if (ins.OpCode == OpCodes.Ldtoken) { var fieldRef = memberReference as FieldReference; if (fieldRef == null) { return(false); } var nextIns = ins.Next; if (nextIns == null) { return(false); } if (nextIns.OpCode != OpCodes.Call) { return(false); } method = nextIns.Operand as MethodReference; if (method == null) { return(false); } return((method.Name == "InitializeArray") && (method.DeclaringType.FullName == "System.Runtime.CompilerServices.RuntimeHelpers")); } method = memberReference as MethodReference; if (method != null) { var methodDef = method.Resolve(context); if ((methodDef != null) && methodDef.HasDexNativeAttribute()) { return(true); } } var field = memberReference as FieldReference; if (field != null) { var fieldDef = field.Resolve(context); if ((fieldDef != null) && fieldDef.HasResourceIdAttribute()) { return(true); } } return(false); }
/// <summary> /// Create default ctors for reachable structs. /// </summary> public void Convert(ReachableContext reachableContext) { // Collect all type var todoTypes = reachableContext.ReachableTypes.Where(NeedsSemanticMethods).ToList(); if (todoTypes.Count == 0) return; foreach (var type in todoTypes) { // Create methods var copyFromMethod = CreateCopyFromMethod(reachableContext, type); CreateCloneMethod(reachableContext, type, copyFromMethod); } }
/// <summary> /// Convert calls to android extension ctors. /// </summary> public void Convert(ReachableContext reachableContext) { this.reachableContext = reachableContext; // Collect all names var methodsWithBody = reachableContext.ReachableTypes.SelectMany(x => x.Methods).Where(m => m.HasBody).ToList(); if (methodsWithBody.Count == 0) return; foreach (var method in methodsWithBody) { Convert(method.Body); } }