예제 #1
0
        /// <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);
        }
예제 #2
0
        /// <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));
            }
        }
예제 #3
0
 /// <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
         });
     }
 }
예제 #4
0
        /// <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);
        }
예제 #6
0
        /// <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));
        }