/// <summary> /// Gets the instance type that calls the given method. /// Create if needed. /// </summary> public DelegateInstanceType GetOrCreateInstance(ISourceLocation sequencePoint, DexTargetPackage targetPackage, XMethodDefinition calledMethod) { DelegateInstanceType result; if (instances.TryGetValue(calledMethod, out result)) { return(result); } // Ensure prototype exists if (invokePrototype == null) { invokePrototype = PrototypeBuilder.BuildPrototype(compiler, targetPackage, interfaceClass, invokeMethod); } // Not found, build it. var builder = new DelegateInstanceTypeBuilder(sequencePoint, compiler, targetPackage, InterfaceClass, invokeMethod, invokePrototype, calledMethod); result = builder.Create(); instances.Add(calledMethod, result); return(result); }
/// <summary> /// Implement the class now that all classes have been created /// </summary> protected override void CreateMembers(DexTargetPackage targetPackage) { base.CreateMembers(targetPackage); // Build default ctor XTypeSystem typeSystem = Compiler.Module.TypeSystem; XSyntheticMethodDefinition ctor = XSyntheticMethodDefinition.Create(XType, XSyntheticMethodFlags.Constructor, "<init>", null, typeSystem.Void); ctor.Body = CreateCtorBody(); Class.Methods.Add(ctor.GetDexMethod(Class, targetPackage)); // Build Invoke method. XMethodDefinition sourceMethod = XType.Methods.Single(x => x.EqualsName("Invoke")); Prototype prototype = PrototypeBuilder.BuildPrototype(Compiler, targetPackage, Class, sourceMethod); MethodDefinition method = new MethodDefinition(Class, sourceMethod.Name, prototype) { AccessFlags = AccessFlags.Public | AccessFlags.Abstract, MapFileId = Compiler.GetNextMapFileId() }; Class.Methods.Add(method); // Find xSource method targetPackage.NameConverter.Record(sourceMethod, method); // If void() delegate, implement java.lang.Runnable if (sourceMethod.ReturnType.IsVoid() && (sourceMethod.Parameters.Count == 0)) { // Implement interface Class.Interfaces.Add(FrameworkReferences.Runnable); // Build run method var run = new MethodDefinition(Class, "run", new Prototype(PrimitiveType.Void)) { AccessFlags = AccessFlags.Public | AccessFlags.Final }; Class.Methods.Add(run); run.Body = new DexLib.Instructions.MethodBody(run, 1) { IncomingArguments = 1, OutgoingArguments = 1 }; var insList = run.Body.Instructions; var rThis = run.Body.Registers[0]; insList.Add(new DexLib.Instructions.Instruction(OpCodes.Invoke_virtual, method, rThis)); insList.Add(new DexLib.Instructions.Instruction(OpCodes.Return_void)); } }
/// <summary> /// Implement the class now that all classes have been created /// </summary> protected override void CreateMembers(DexTargetPackage targetPackage) { // Build ctors foreach (var baseCtor in GetBaseClassCtors()) { // Build ctor var prototype = PrototypeBuilder.BuildPrototype(Compiler, targetPackage, null, baseCtor); var ctor = new MethodDefinition(Class, "<init>", prototype); ctor.AccessFlags = AccessFlags.Public | AccessFlags.Constructor; Class.Methods.Add(ctor); // Create ctor body var ctorBody = CreateCtorBody(prototype); targetPackage.Record(new CompiledMethod { DexMethod = ctor, RLBody = ctorBody }); } }
/// <summary> /// Create the current type as class definition. /// </summary> public void Create(ClassDefinition declaringClass, DexTargetPackage targetPackage) { // Find xMethod xMethod = XBuilder.AsMethodDefinition(compiler.Module, method); // Create method definition dmethod = new DexLib.MethodDefinition(); dmethod.Name = GetMethodName(method, targetPackage); dmethod.MapFileId = compiler.GetNextMapFileId(); AddMethodToDeclaringClass(declaringClass, dmethod, targetPackage); targetPackage.Record(xMethod, dmethod); // Set access flags SetAccessFlags(dmethod, method); // Create prototype dmethod.Prototype = PrototypeBuilder.BuildPrototype(compiler, targetPackage, declaringClass, xMethod); }
/// <summary> /// Implement the class now that all classes have been created /// </summary> protected override void CreateMembers(DexTargetPackage targetPackage) { // Build ctors foreach (var baseCtor in GetBaseClassCtors()) { // TODO: does this make sense? after all, we derive from object. // probalby one should just remove this code, and generate a // defaul constructor. var prototype = PrototypeBuilder.BuildPrototype(Compiler, targetPackage, null, baseCtor); var ctor = new MethodDefinition(Class, "<init>", prototype); ctor.AccessFlags = AccessFlags.Public | AccessFlags.Constructor; Class.Methods.Add(ctor); // Create ctor body var ctorBody = CreateCtorBody(prototype); targetPackage.Record(new CompiledMethod { DexMethod = ctor, RLBody = ctorBody }); } // build original type field // Create field definition // NOTE: at the moment the underlying type is both defined as a type and in the annotation. // remove one or the other when we have determined which is the better way. var dfield = new Dot42.DexLib.FieldDefinition(); dfield.Owner = Class; dfield.Name = "underlying$"; dfield.IsSynthetic = true; dfield.IsFinal = true; dfield.IsStatic = true; dfield.IsPublic = true; dfield.Type = Compiler.Module.TypeSystem.Type.GetClassReference(targetPackage); dfield.Value = _underlyingBuilder.Class; Class.Fields.Add(dfield); }
/// <summary> /// Implement the class now that all classes have been created /// </summary> protected override void CreateMembers(DexTargetPackage targetPackage) { // Build ctors foreach (var baseCtor in GetBaseClassCtors()) { // Build ctor var prototype = PrototypeBuilder.BuildPrototype(Compiler, targetPackage, null, baseCtor); var ctor = new MethodDefinition(Class, "<init>", prototype); ctor.AccessFlags = AccessFlags.Public | AccessFlags.Constructor; Class.Methods.Add(ctor); // Create ctor body var ctorBody = CreateCtorBody(prototype); targetPackage.Record(new CompiledMethod { DexMethod = ctor, RLBody = ctorBody }); } // build original type field // Create field definition var dfield = new Dot42.DexLib.FieldDefinition(); dfield.Owner = Class; dfield.Name = "underlying$"; dfield.IsSynthetic = true; dfield.IsFinal = true; dfield.IsStatic = true; dfield.IsPublic = true; dfield.Type = Compiler.Module.TypeSystem.Type.GetClassReference(targetPackage); // not sure if GetClassReference is the best way to go forward here. // might depend on the sort order of the class builders. var underlyingType = XBuilder.AsTypeReference(Compiler.Module, Type); dfield.Value = underlyingType.GetClassReference(targetPackage); Class.Fields.Add(dfield); }
/// <summary> /// Create the current type as class definition. /// </summary> internal static DelegateInstanceType Create( ISourceLocation sequencePoint, AssemblyCompiler compiler, DexTargetPackage targetPackage, ClassDefinition delegateClass, XMethodDefinition invokeMethod, Prototype invokePrototype, XMethodDefinition equalsMethod, Prototype equalsPrototype, XMethodDefinition calledMethod) { // Prepare called method var target = targetPackage.DexFile; var owner = target.GetClass(calledMethod.DeclaringType.GetClassReference(targetPackage).Fullname) ?? targetPackage.GetOrCreateGeneratedCodeClass(); var calledMethodPrototype = PrototypeBuilder.BuildPrototype(compiler, targetPackage, owner, calledMethod); var calledMethodRef = calledMethod.GetReference(targetPackage); if (calledMethod.DeclaringType.HasDexImportAttribute()) { // Delegate method is a Dex import method } else { // Delegate method is a .NET method var calledDexMethod = owner.Methods.Single(x => (x.Name == calledMethodRef.Name) && (x.Prototype.Equals(calledMethodRef.Prototype))); if (calledDexMethod.IsPrivate) { calledDexMethod.IsPrivate = false; calledDexMethod.IsProtected = true; } } var @class = new ClassDefinition(); @class.Name = CreateInstanceTypeName(owner); @class.Namespace = owner.Namespace; @class.AccessFlags = AccessFlags.Public | AccessFlags.Final; owner.InnerClasses.Add(@class); // Set super class @class.SuperClass = delegateClass; // Implement delegate interface //@class.Interfaces.Add(delegateInterface); // Get type of instance XTypeDefinition instanceType = calledMethod.DeclaringType; TypeReference instanceTypeRef = instanceType.GetReference(targetPackage); // Add instance field FieldDefinition instanceField = null; if (!calledMethod.IsStatic) { instanceField = new FieldDefinition(); instanceField.Name = "instance"; instanceField.Owner = @class; instanceField.Type = instanceTypeRef; instanceField.AccessFlags = AccessFlags.Private | AccessFlags.Final; @class.Fields.Add(instanceField); } // Add ctor var ctor = new Dot42.DexLib.MethodDefinition(); ctor.Owner = @class; ctor.Name = "<init>"; ctor.AccessFlags = AccessFlags.Public | AccessFlags.Constructor; ctor.Prototype = new Prototype(PrimitiveType.Void); if (!calledMethod.IsStatic) { ctor.Prototype.Parameters.Add(new Parameter(instanceTypeRef, "this")); } @class.Methods.Add(ctor); // Create ctor body var ctorBody = CreateCtorBody(calledMethod, instanceField, delegateClass); targetPackage.Record(new CompiledMethod() { DexMethod = ctor, RLBody = ctorBody }); // Add Invoke method var invoke = new Dot42.DexLib.MethodDefinition(@class, "Invoke", invokePrototype) { AccessFlags = AccessFlags.Public }; @class.Methods.Add(invoke); // Create body var invokeBody = CreateInvokeBody(sequencePoint, compiler, targetPackage, calledMethod, invokeMethod, invokePrototype, calledMethodPrototype, instanceField, delegateClass); targetPackage.Record(new CompiledMethod() { DexMethod = invoke, RLBody = invokeBody }); // Add Equals method if (null != equalsMethod) { var equals = new Dot42.DexLib.MethodDefinition(@class, "equals", equalsPrototype) { AccessFlags = AccessFlags.Public }; @class.Methods.Add(equals); // Create body if (!calledMethod.IsStatic) { var equalsBody = CreateEqualsBody(sequencePoint, compiler, targetPackage, equalsMethod, equalsPrototype, instanceField, @class); targetPackage.Record(new CompiledMethod() { DexMethod = equals, RLBody = equalsBody }); } else { var equalsBody = CreateEqualsBody(); targetPackage.Record(new CompiledMethod() { DexMethod = equals, RLBody = equalsBody }); } } return(new DelegateInstanceType(calledMethod, @class, ctor)); }
public DelegateInstanceType Create() { instanceField = null; // actually at the momennt, we are not called multiple times... genericMethodTypeFields.Clear(); genericInstanceTypeFields.Clear(); // Prepare called method var target = targetPackage.DexFile; var owner = target.GetClass(calledMethod.DeclaringType.GetClassReference(targetPackage).Fullname) ?? targetPackage.GetOrCreateGeneratedCodeClass(); var calledMethodPrototype = PrototypeBuilder.BuildPrototype(compiler, targetPackage, owner, calledMethod); var calledMethodRef = calledMethod.GetReference(targetPackage); if (calledMethod.DeclaringType.HasDexImportAttribute()) { // Delegate method is a Dex import method } else { // Delegate method is a .NET method var calledDexMethod = owner.Methods.Single(x => (x.Name == calledMethodRef.Name) && (x.Prototype.Equals(calledMethodRef.Prototype))); if (calledDexMethod.IsPrivate) { calledDexMethod.IsPrivate = false; calledDexMethod.IsProtected = true; } } var @class = new ClassDefinition { Name = CreateInstanceTypeName(owner), Namespace = owner.Namespace, AccessFlags = AccessFlags.Public | AccessFlags.Final, MapFileId = compiler.GetNextMapFileId(), }; owner.AddInnerClass(@class); // Set super class @class.SuperClass = delegateClass; // Implement delegate interface //@class.Interfaces.Add(delegateInterface); // Get type of instance XTypeDefinition instanceType = calledMethod.DeclaringType; TypeReference instanceTypeRef = instanceType.GetReference(targetPackage); // Add ctor var ctor = new MethodDefinition { Owner = @class, Name = "<init>", AccessFlags = AccessFlags.Public | AccessFlags.Constructor, Prototype = new Prototype(PrimitiveType.Void), }; ctor.Prototype.Unfreeze(); if (!calledMethod.IsStatic) { ctor.Prototype.Parameters.Add(new Parameter(instanceTypeRef, "this")); } PrototypeBuilder.AddGenericParameters(compiler, targetPackage, calledMethod, ctor.Prototype); ctor.Prototype.Freeze(); @class.Methods.Add(ctor); // Add methodInfo field methodInfoField = new FieldDefinition(); methodInfoField.Name = "methodInfo"; methodInfoField.Owner = @class; methodInfoField.Type = compiler.GetDot42InternalType("System.Reflection", "MethodInfo").GetReference(targetPackage); methodInfoField.AccessFlags = AccessFlags.Private | AccessFlags.Final | AccessFlags.Static; @class.Fields.Add(methodInfoField); // Add instance field & getTargetImpl method if (!calledMethod.IsStatic) { instanceField = new FieldDefinition(); instanceField.Name = "instance"; instanceField.Owner = @class; instanceField.Type = instanceTypeRef; instanceField.AccessFlags = AccessFlags.Private | AccessFlags.Final; @class.Fields.Add(instanceField); AddMethod(@class, "GetTargetImpl", new Prototype(FrameworkReferences.Object), AccessFlags.Protected, CreateGetTargetImplBody()); } // Add generic instance type and method fields var gtpa = compiler.GetDot42InternalType(InternalConstants.GenericTypeParameterAnnotation).GetClassReference(targetPackage); var gmpa = compiler.GetDot42InternalType(InternalConstants.GenericMethodParameterAnnotation).GetClassReference(targetPackage); foreach (var parameter in ctor.Prototype.Parameters) { bool isGtpa = parameter.Annotations.Any(a => a.Type.Equals(gtpa)); bool isGmpa = parameter.Annotations.Any(a => a.Type.Equals(gmpa)); if (isGmpa || isGtpa) { var list = isGtpa ? genericInstanceTypeFields : genericMethodTypeFields; var field = new FieldDefinition(); field.Name = isGtpa ? "$git" : "$gmt"; if (parameter.Type.Equals(FrameworkReferences.Class)) { field.Name += list.Count + 1; } field.Owner = @class; field.Type = parameter.Type; field.AccessFlags = AccessFlags.Private | AccessFlags.Final; @class.Fields.Add(field); list.Add(field); } } // Create ctor body var ctorBody = CreateCtorBody(); targetPackage.Record(new CompiledMethod() { DexMethod = ctor, RLBody = ctorBody }); // add class static ctor AddMethod(@class, "<clinit>", new Prototype(PrimitiveType.Void), AccessFlags.Public | AccessFlags.Constructor | AccessFlags.Static, CreateCctorBody()); // Add Invoke method AddMethod(@class, "Invoke", invokePrototype, AccessFlags.Public, CreateInvokeBody(calledMethodPrototype)); // Add Equals method var typeOnlyEqualsSuffices = calledMethod.IsStatic && !calledMethod.NeedsGenericInstanceTypeParameter && !calledMethod.NeedsGenericInstanceMethodParameter; var equalsBody = typeOnlyEqualsSuffices ? CreateEqualsCheckTypeOnlyBody(@class) : CreateEqualsBody(@class); var equalsPrototype = new Prototype(PrimitiveType.Boolean, new Parameter(multicastDelegateClass, "other")); AddMethod(@class, "EqualsWithoutInvocationList", equalsPrototype, AccessFlags.Protected, equalsBody); if (!typeOnlyEqualsSuffices) { var hashCodePrototype = new Prototype(PrimitiveType.Int); AddMethod(@class, "HashCodeWithoutInvocationList", hashCodePrototype, AccessFlags.Protected, CreateHashCodeBody(@class)); } var clonePrototype = new Prototype(multicastDelegateClass, new Parameter(new ArrayType(multicastDelegateClass), "invocationList"), new Parameter(PrimitiveType.Int, "invocationListLength")); AddMethod(@class, "CloneWithNewInvocationList", clonePrototype, AccessFlags.Protected, CreateCloneBody(ctor, @class)); AddMethod(@class, "GetMethodInfoImpl", new Prototype(methodInfoField.Type), AccessFlags.Protected, CreateGetMethodInfoImplBody()); return(new DelegateInstanceType(calledMethod, @class, ctor)); }