예제 #1
0
        public MethodDisassembly(MethodDefinition methodDef, MapFileLookup mapFile = null, TypeEntry typeEntry = null, MethodEntry methodEntry = null)
        {
            _typeEntry = typeEntry;
            _methodEntry = methodEntry;
            _methodDef = methodDef;
            _mapFile = mapFile;

            JumpTargetOffsets=new HashSet<int>();
            ExceptionHandlerOffsets = new HashSet<int>();

            if (methodDef.Body != null)
            {
                foreach (var i in methodDef.Body.Instructions)
                {
                    var op = i.Operand as Instruction;
                    if (op != null)
                        JumpTargetOffsets.Add(op.Offset);
                }
                foreach (var e in methodDef.Body.Exceptions)
                {
                    foreach(var c in e.Catches)
                        ExceptionHandlerOffsets.Add(c.Instruction.Offset);
                    if (e.CatchAll != null)
                        ExceptionHandlerOffsets.Add(e.CatchAll.Offset);
                }
            }

            Format = FormatOptions.Default;
        }
예제 #2
0
 /// <summary>
 /// Create code to load a value from an annotation interface.
 /// </summary>
 /// <returns>The register(s) holding the value</returns>
 private static Register[] CreateLoadValueSequence(
     ISourceLocation seqp,
     MethodBody body,
     TypeReference valueType,
     Register annotationReg,
     MethodDefinition getter)
 {
     if (valueType.IsWide())
     {
         Tuple <Register, Register> regs = body.AllocateWideRegister(RCategory.Temp);
         body.Instructions.Add(seqp, RCode.Invoke_interface, getter, annotationReg);
         body.Instructions.Add(seqp, RCode.Move_result_wide, regs.Item1);
         return(new[] { regs.Item1, regs.Item2 });
     }
     if (valueType is PrimitiveType)
     {
         Register reg = body.AllocateRegister(RCategory.Temp, RType.Value);
         body.Instructions.Add(seqp, RCode.Invoke_interface, getter, annotationReg);
         body.Instructions.Add(seqp, RCode.Move_result, reg);
         return(new[] { reg });
     }
     else
     {
         Register reg = body.AllocateRegister(RCategory.Temp, RType.Object);
         body.Instructions.Add(seqp, RCode.Invoke_interface, getter, annotationReg);
         body.Instructions.Add(seqp, RCode.Move_result_object, reg);
         return(new[] { reg });
     }
 }
예제 #3
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>", 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 };
            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));
            }
        }
        public MethodBody GetMethodBody(MethodDefinition targetMethod, XMethodDefinition sourceMethod)
        {
            var javaType = (XBuilder.JavaTypeDefinition) sourceMethod.DeclaringType;
            var className = javaType.ClassFile.ClassName;
            var source = javaType.ClassFile.Loader.TryGetClassSource(className);

            if (source == null)
                return null;

            DexLookup dex = GetOrCreateDex(source, waitForResult: true);
            var methodDef = dex.GetMethod(targetMethod.Owner.Fullname, targetMethod.Name, targetMethod.Prototype.ToSignature());
            return methodDef == null ? null : methodDef.Body;
        }
예제 #5
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 });                
     }
 }
        public CacheEntry GetFromCache(MethodDefinition targetMethod, XMethodDefinition sourceMethod, AssemblyCompiler compiler, DexTargetPackage targetPackage)
        {
            var ret = GetFromCacheImpl(targetMethod, sourceMethod, compiler, targetPackage);

            if (ret != null)
            {
                Interlocked.Increment(ref statCacheHits);
            }
            else
            {
                Interlocked.Increment(ref statCacheMisses);
            }

            return(ret);
        }
예제 #7
0
        public MethodBody GetMethodBody(MethodDefinition targetMethod, XMethodDefinition sourceMethod)
        {
            var javaType  = (XBuilder.JavaTypeDefinition)sourceMethod.DeclaringType;
            var className = javaType.ClassFile.ClassName;
            var source    = javaType.ClassFile.Loader.TryGetClassSource(className);

            if (source == null)
            {
                return(null);
            }

            DexLookup dex       = GetOrCreateDex(source, waitForResult: true);
            var       methodDef = dex.GetMethod(targetMethod.Owner.Fullname, targetMethod.Name, targetMethod.Prototype.ToSignature());

            return(methodDef == null ? null : methodDef.Body);
        }
예제 #8
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));
            }
        }
예제 #9
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
         });
     }
 }
예제 #10
0
        /// <summary>
        /// Create a method body for the given method.
        /// </summary>
        internal static MethodBody TranslateToRL(AssemblyCompiler compiler, DexTargetPackage targetPackage, MethodSource source, MethodDefinition dmethod, bool generateSetNextInstructionCode, out CompiledMethod compiledMethod)
        {
            try
            {
#if DEBUG
                //Debugger.Launch();
                if ((source.Method != null) && (source.Method.Name == "test6"))
                {
                    //Debugger.Launch();
                }
#endif

                // Create Ast
                var optimizedAst = CreateOptimizedAst(compiler, source, generateSetNextInstructionCode);

                // Generate RL code
                var rlBody = new MethodBody(source);
                var rlGenerator = new AstCompilerVisitor(compiler, source, targetPackage, dmethod, rlBody);
                optimizedAst.Accept(rlGenerator, null);
                rlGenerator.Complete();

                // Should we add return_void?
                if (source.ReturnsVoid)
                {
                    var instructions = rlBody.Instructions;
                    if ((instructions.Count == 0) || (instructions.Last().Code != RCode.Return_void && instructions.Last().Code != RCode.Throw))
                    {
                        instructions.Add(new RL.Instruction(RCode.Return_void) { SequencePoint = source.GetLastSourceLine() });
                    }
                }

                // Record results
                compiledMethod = targetPackage.Record(source, rlBody, rlGenerator.Frame);

                return rlBody;
            }
            catch (Exception ex)
            {
                // Forward exception with more information
                var msg = string.Format("Error while compiling {0} in {1}: {2}", source.FullName, source.DeclaringTypeFullName, ex.Message);
                throw new CompilerException(msg, ex);
            }
        }
예제 #11
0
파일: Verifier.cs 프로젝트: rfcclub/dot42
 /// <summary>
 /// Verify the given method
 /// </summary>
 private void VerifyMethod(MethodDefinition method)
 {
     if (method.Body == null)
     {
         if (method.IsConstructor)
         {
             onError(string.Format("Constructor has no body: {0}", method));
         }
     }
     else
     {
         foreach (var handler in method.Body.Exceptions)
         {
             if (handler.TryEnd.Offset < handler.TryStart.Offset)
             {
                 onError(string.Format("Invalid exception handler 0x{0:X4}-0x{1:X4} in {2}", handler.TryStart.Offset,
                                       handler.TryEnd.Offset, method.Name));
             }
         }
     }
 }
        /// <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);
        }
예제 #13
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);
        }
        public MethodBodyDisassemblyFormatter(MethodDefinition methodDef, MapFileLookup mapFile)
        {
            _methodDef = methodDef;
            _mapFile = mapFile;

            TypeEntry typeEntry = null;
            MethodEntry methodEntry = null;

            if (mapFile != null)
            {
                typeEntry = mapFile.GetTypeByNewName(methodDef.Owner.Fullname);
                if (typeEntry != null)
                {
                    methodEntry = typeEntry.FindDexMethod(methodDef.Name, methodDef.Prototype.ToSignature());
                }
            }

            _dissassembly = new MethodDisassembly(methodDef, mapFile, typeEntry, methodEntry);

            _sourceDocument = new Lazy<string[]>(() =>
            {
                if (_dissassembly.MethodEntry == null)
                    return null;
                var pos = _mapFile.GetSourceCodePositions(_dissassembly.MethodEntry).FirstOrDefault();
                if (pos == null)
                    return null;

                try
                {
                    return File.ReadAllLines(pos.Document.Path);
                }
                catch (Exception)
                {
                    return null;
                }
            });
        }
예제 #15
0
        private static MethodDefinition CreateFactoryMethod(AssemblyCompiler compiler, DexTargetPackage targetPackage, CustomAttribute attribute, AttributeAnnotationMapping mapping)
        {
            var             targetClass      = mapping.AttributeClass; // is this really the right place for the factory methods?
            ISourceLocation seqp             = null;
            var             attributeTypeDef = attribute.AttributeType.Resolve();

            // create method
            string           methodName = CreateAttributeFactoryMethodName(targetClass);
            MethodDefinition method     = new MethodDefinition(targetClass, methodName, new Prototype(mapping.AttributeClass));

            method.AccessFlags = AccessFlags.Public | AccessFlags.Static | AccessFlags.Synthetic;
            targetClass.Methods.Add(method);

            // create method body
            MethodBody body = new MethodBody(null);
            // Allocate attribute
            Register attributeReg = body.AllocateRegister(RCategory.Temp, RType.Object);

            body.Instructions.Add(seqp, RCode.New_instance, mapping.AttributeClass, attributeReg);

            // collect ctor arguments
            List <Register> ctorArgRegs = new List <Register>()
            {
                attributeReg
            };

            foreach (var p in attribute.ConstructorArguments)
            {
                XTypeReference xType     = XBuilder.AsTypeReference(compiler.Module, p.Type);
                Register[]     valueRegs = CreateInitializeValueInstructions(seqp, body, xType, p, compiler, targetPackage);
                ctorArgRegs.AddRange(valueRegs);
            }
            // Invoke ctor
            DexLib.MethodReference dctor = attribute.Constructor.GetReference(targetPackage, compiler.Module);
            body.Instructions.Add(seqp, RCode.Invoke_direct, dctor, ctorArgRegs.ToArray());

            // set field values
            foreach (var p in attribute.Fields)
            {
                var field  = GetField(attributeTypeDef, p.Name);
                var xField = XBuilder.AsFieldReference(compiler.Module, field);

                Register[] valueRegs = CreateInitializeValueInstructions(seqp, body, xField.FieldType, p.Argument, compiler, targetPackage);
                body.Instructions.Add(seqp, xField.FieldType.IPut(), xField.GetReference(targetPackage),
                                      valueRegs[0], attributeReg);
            }

            // set property values
            foreach (var p in attribute.Properties)
            {
                PropertyDefinition property = GetSettableProperty(attributeTypeDef, p.Name);
                XTypeReference     xType    = XBuilder.AsTypeReference(compiler.Module, property.PropertyType);

                Register[]        valueRegs  = CreateInitializeValueInstructions(seqp, body, xType, p.Argument, compiler, targetPackage);
                XMethodDefinition xSetMethod = XBuilder.AsMethodDefinition(compiler.Module, property.SetMethod);
                body.Instructions.Add(seqp, xSetMethod.Invoke(xSetMethod, null),
                                      xSetMethod.GetReference(targetPackage),
                                      new[] { attributeReg }.Concat(valueRegs).ToArray());
            }

            // Return attribute
            body.Instructions.Add(seqp, RCode.Return_object, attributeReg);

            // Register method body
            targetPackage.Record(new CompiledMethod()
            {
                DexMethod = method, RLBody = body
            });

            // Return method
            return(method);
        }
 /// <summary>
 /// Default ctor
 /// </summary>
 internal AttributeCtorMapping(MethodDefinition builder, List<MethodDefinition> argumentGetters)
 {
     this.Builder = builder;
     ArgumentGetters = argumentGetters;
 }
예제 #17
0
        /// <summary>
        /// Create a frame for the given method
        /// </summary>
        internal AstInvocationFrame(DexTargetPackage targetPackage, MethodDefinition method, MethodSource source, MethodBody body) 
        {
            this.targetPackage = targetPackage;
            this.body = body;
            this.body = body;
            Debug.Assert(!body.Registers.Any());

            var prototypeParamOffset = 0;
            var prototype = method.Prototype;

            if (source.IsDotNet)
            {
                var ilMethod = source.ILMethod;

                // Allocate this
                if (!method.IsStatic)
                {
                    thisArgument = (ArgumentRegisterSpec) Allocate(method.Owner, true, RCategory.Argument, ilMethod.Body.ThisParameter);
                    arguments.Add(thisArgument);
                }
                else if (ilMethod.IsAndroidExtension() && !ilMethod.IsStatic)
                {
                    prototypeParamOffset++;
                    var type = ilMethod.DeclaringType.GetReference(targetPackage, source.Method.Module);
                    thisArgument = (ArgumentRegisterSpec) Allocate(type, true, RCategory.Argument, ilMethod.Body.ThisParameter);
                    arguments.Add(thisArgument);
                }
                // Allocate arguments
                var paramCount = ilMethod.Parameters.Count;
                for (var i = 0; i < paramCount; i++)
                {
                    var p = ilMethod.Parameters[i];
                    var type = prototype.Parameters[prototypeParamOffset++].Type;
                    arguments.Add((ArgumentRegisterSpec) Allocate(type, false, RCategory.Argument, p));
                }
            }
            else if (source.IsJava)
            {
                var javaMethod = source.JavaMethod;

                // Allocate this
                var code = javaMethod.Attributes.OfType<CodeAttribute>().First();
                if (!method.IsStatic)
                {
                    thisArgument = (ArgumentRegisterSpec)Allocate(method.Owner, true, RCategory.Argument, code.ThisParameter);
                    arguments.Add(thisArgument);
                }
                // Allocate arguments
                foreach (var p in code.Parameters)
                {
                    var type = prototype.Parameters[prototypeParamOffset++].Type;
                    arguments.Add((ArgumentRegisterSpec)Allocate(type, false, RCategory.Argument, p.Item2));
                }
            }
            else if (source.IsAst)
            {
                // Allocate this
                if (!method.IsStatic)
                {
                    thisArgument = (ArgumentRegisterSpec)Allocate(method.Owner, true, RCategory.Argument, null);
                    arguments.Add(thisArgument);
                }
                // Allocate arguments
                foreach (var p in ((XSyntheticMethodDefinition)source.Method).AstParameters)
                {
                    var type = prototype.Parameters[prototypeParamOffset++].Type;
                    arguments.Add((ArgumentRegisterSpec)Allocate(type, false, RCategory.Argument, p));
                }
            }
            else
            {
                throw new ArgumentException("Unknown source");
            }

            // Add GenericInstanceType parameter (if any)
            if (source.Method.NeedsGenericInstanceTypeParameter)
            {
                var type = prototype.GenericInstanceTypeParameter.Type;
                GenericInstanceTypeArgument = (ArgumentRegisterSpec) Allocate(type, false, RCategory.Argument, null);
                arguments.Add(GenericInstanceTypeArgument);                
            }
            // Add GenericInstanceMethod parameter (if any)
            if (source.Method.NeedsGenericInstanceMethodParameter)
            {
                var type = prototype.GenericInstanceMethodParameter.Type;
                GenericInstanceMethodArgument = (ArgumentRegisterSpec) Allocate(type, false, RCategory.Argument, null);
                arguments.Add(GenericInstanceMethodArgument);
            }
            // Check register count
            var expected = prototype.Parameters.Sum(x => x.Type.IsWide() ? 2 : 1);
            if (!method.IsStatic) expected++;
            if (expected != body.Registers.Count())
            {
                throw new ArgumentException(string.Format("Expected {0} registers, found {1} (in {2})", expected, body.Registers.Count(), method));
            }
        }
예제 #18
0
        /// <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);
        }
예제 #19
0
        /// <summary>
        /// Create an annotation interface.
        /// </summary>
        internal static AttributeAnnotationInterface Create(
            ISourceLocation sequencePoint,
            AssemblyCompiler compiler,
            DexTargetPackage targetPackage,
            TypeDefinition attributeType,
            ClassDefinition attributeClass)
        {
            // Create class
            ClassDefinition @interface = new ClassDefinition();

            @interface.Name        = CreateAnnotationTypeName(attributeClass);
            @interface.Namespace   = attributeClass.Namespace;
            @interface.AccessFlags = AccessFlags.Public | AccessFlags.Abstract | AccessFlags.Interface | AccessFlags.Annotation;
            @interface.Owner       = attributeClass;
            attributeClass.InnerClasses.Add(@interface);

            // Set super class
            @interface.SuperClass = new ClassReference("java/lang/Object");

            // Implement Dot42.Internal.IAttribute
            @interface.Interfaces.Add(new ClassReference("java/lang/annotation/Annotation"));

            // Prepare result
            AttributeAnnotationInterface result = new AttributeAnnotationInterface(@interface);

            // Add methods from IAttribute
            XModel.XTypeDefinition baseIntfType = compiler.GetDot42InternalType("IAttribute").Resolve();
            foreach (XModel.XMethodDefinition imethod in baseIntfType.Methods)
            {
                if (imethod.Parameters.Count > 0)
                {
                    throw new CompilerException(string.Format("Invalid IAttribute method {0}", imethod));
                }
                string           methodName = NameConverter.GetConvertedName(imethod);
                TypeReference    dfieldType = imethod.ReturnType.GetReference(targetPackage);
                MethodDefinition method     = new MethodDefinition(@interface, methodName, new Prototype(dfieldType));
                method.AccessFlags = AccessFlags.Public | AccessFlags.Abstract;
                @interface.Methods.Add(method);
            }

            // Add field mapping
            foreach (var field in attributeType.Fields.Where(x => x.IsReachable && x.IsPublic))
            {
                string           methodName = CreateGetMethodName(NameConverter.GetConvertedName(field), result);
                TypeReference    dfieldType = field.FieldType.GetReference(targetPackage, compiler.Module);
                MethodDefinition method     = new MethodDefinition(@interface, methodName, new Prototype(dfieldType));
                method.AccessFlags = AccessFlags.Public | AccessFlags.Abstract;
                result.FieldToGetMethodMap.Add(field, method);
                @interface.Methods.Add(method);
            }

            // Add property mapping
            foreach (var property in attributeType.Properties.Where(x => x.IsReachable && (x.SetMethod != null) && (x.SetMethod.IsPublic) && x.SetMethod.IsReachable))
            {
                string           methodName = CreateGetMethodName(NameConverter.GetConvertedName(property), result);
                TypeReference    dpropType  = property.PropertyType.GetReference(targetPackage, compiler.Module);
                MethodDefinition method     = new MethodDefinition(@interface, methodName, new Prototype(dpropType));
                method.AccessFlags = AccessFlags.Public | AccessFlags.Abstract;
                result.PropertyToGetMethodMap.Add(property, method);
                @interface.Methods.Add(method);
            }

            // Add ctor mapping
            var argIndex = 0;

            foreach (var ctor in attributeType.Methods.Where(x => (x.Name == ".ctor") && x.IsReachable))
            {
                // Add methods for the ctor arguments
                List <MethodDefinition> paramGetMethods = new List <MethodDefinition>();
                foreach (ParameterDefinition p in ctor.Parameters)
                {
                    string           methodName = CreateGetMethodName("c" + argIndex++, result);
                    TypeReference    dparamType = p.ParameterType.GetReference(targetPackage, compiler.Module);
                    MethodDefinition method     = new MethodDefinition(@interface, methodName, new Prototype(dparamType));
                    method.AccessFlags = AccessFlags.Public | AccessFlags.Abstract;
                    @interface.Methods.Add(method);
                    paramGetMethods.Add(method);
                }

                // Add a builder method
                MethodDefinition buildMethod = CreateBuildMethod(sequencePoint, ctor, paramGetMethods, compiler, targetPackage, attributeClass, result);
                result.CtorMap.Add(ctor, new AttributeCtorMapping(buildMethod, paramGetMethods));
            }

            // Create default values annotation
            Annotation defAnnotation = CreateDefaultAnnotation(result);

            result.AnnotationInterfaceClass.Annotations.Add(defAnnotation);

            return(result);
        }
예제 #20
0
        /// <summary>
        /// Note that referencing operands, i.e. TypeReferences, FieldReference or
        /// MethodRefrences are not cloned, but only shallow copied.
        /// If you indend to modify those operand values themself, be sure to clone
        /// them beforehand. 
        /// </summary>
        public static MethodBody Clone(MethodDefinition targetMethod, MethodDefinition sourceMethod)
        {
            var sourceBody = sourceMethod.Body;

            MethodBody body = new MethodBody(targetMethod, sourceBody.Registers.Count)
            {
                IncomingArguments = sourceBody.IncomingArguments,
                OutgoingArguments = sourceBody.OutgoingArguments
            };

            foreach (var sourceIns in sourceBody.Instructions)
            {
                var ins = new Instruction(sourceIns.OpCode);

                foreach (var r in sourceIns.Registers)
                    ins.Registers.Add(body.Registers[r.Index]);

                ins.Offset = sourceIns.Offset;
                ins.SequencePoint = ins.SequencePoint;

                ins.Operand = sourceIns.Operand;

                body.Instructions.Add(ins);
            }

            // fix instruction references

            var insByOffset = body.Instructions.ToDictionary(i => i.Offset);

            foreach (var ins in body.Instructions)
            {
                var targetIns = ins.Operand as Instruction;
                var packedSwitch = ins.Operand as PackedSwitchData;
                var sparseSwitch = ins.Operand as SparseSwitchData;

                if (targetIns != null)
                {
                    ins.Operand = insByOffset[targetIns.Offset];
                }
                else if (packedSwitch != null)
                {
                    var ps = new PackedSwitchData(packedSwitch.Targets.Select(si => insByOffset[si.Offset]));
                    ps.FirstKey = packedSwitch.FirstKey;
                    ins.Operand = ps;
                }
                else if (sparseSwitch != null)
                {
                    var ss = new SparseSwitchData();
                    foreach (var ssd in sparseSwitch.Targets)
                    {
                        ss.Targets.Add(ssd.Key, insByOffset[ssd.Value.Offset]);
                    }
                    ins.Operand = ss;
                }
            }


            foreach (var sourceEx in sourceBody.Exceptions)
            {
                var ex = new ExceptionHandler();
                if (sourceEx.TryStart != null)
                    ex.TryStart = insByOffset[sourceEx.TryStart.Offset];
                if (sourceEx.TryEnd != null)
                    ex.TryEnd   = insByOffset[sourceEx.TryEnd.Offset];
                if (sourceEx.CatchAll != null)
                    ex.CatchAll = insByOffset[sourceEx.CatchAll.Offset];

                foreach (var sourceCatch in sourceEx.Catches)
                {
                    var c = new Catch
                    {
                        Type = sourceCatch.Type,
                        Instruction = insByOffset[sourceCatch.Instruction.Offset]
                    };
                    ex.Catches.Add(c);
                }

                body.Exceptions.Add(ex);
            }

            if (sourceBody.DebugInfo != null)
            {
                var di = body.DebugInfo = new DebugInfo(body);

                di.LineStart = sourceBody.DebugInfo.LineStart;
                di.Parameters = sourceBody.DebugInfo.Parameters.ToList();

                foreach (var sourceInstruction in sourceBody.DebugInfo.DebugInstructions)
                {
                    di.DebugInstructions.Add(new DebugInstruction(sourceInstruction.OpCode,
                        sourceInstruction.Operands.ToList()));
                }
            }

            return body;
        }
예제 #21
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())
            {
                // 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);

        }
예제 #22
0
 /// <summary>
 /// Is other equal to this?
 /// </summary>
 public bool Equals(MethodDefinition other)
 {
     // Should be enough (ownership)
     return base.Equals(other);
 }
        /// <summary>
        /// Create an annotation interface.
        /// </summary>
        internal static AttributeAnnotationInterface Create(
            ISourceLocation sequencePoint,
            AssemblyCompiler compiler,
            DexTargetPackage targetPackage,
            TypeDefinition attributeType,
            ClassDefinition attributeClass)
        {
            // Create class
            ClassDefinition @interface = new ClassDefinition();
            @interface.Name = CreateAnnotationTypeName(attributeClass);
            @interface.Namespace = attributeClass.Namespace;
            @interface.AccessFlags = AccessFlags.Public | AccessFlags.Abstract | AccessFlags.Interface | AccessFlags.Annotation;
            @interface.Owner = attributeClass;
            attributeClass.AddInnerClass(@interface);

            // Set super class
            @interface.SuperClass = FrameworkReferences.Object;

            // Implement Dot42.Internal.IAttribute
            @interface.Interfaces.Add(new ClassReference("java/lang/annotation/Annotation"));

            // Prepare result
            AttributeAnnotationInterface result = new AttributeAnnotationInterface(@interface);

            // Add methods from IAttribute
            XModel.XTypeDefinition baseIntfType = compiler.GetDot42InternalType("IAttribute").Resolve();
            foreach (XModel.XMethodDefinition imethod in baseIntfType.Methods)
            {
                if (imethod.Parameters.Count > 0) 
                    throw new CompilerException(string.Format("Invalid IAttribute method {0}", imethod));
                string methodName = NameConverter.GetConvertedName(imethod);
                TypeReference dfieldType = imethod.ReturnType.GetReference(targetPackage);
                MethodDefinition method = new MethodDefinition(@interface, methodName, new Prototype(dfieldType));
                method.AccessFlags = AccessFlags.Public | AccessFlags.Abstract;
                @interface.Methods.Add(method);                
            }

            TypeDefinition currentType = attributeType;

            while (currentType != null && currentType.FullName != typeof(Attribute).FullName)
            {
                // Add field mapping
                foreach (var field in currentType.Fields.Where(x => x.IsReachable && x.IsPublic))
                {
                    string methodName = CreateGetMethodName(NameConverter.GetConvertedName(field), result);
                    MethodDefinition method = new MethodDefinition(@interface, methodName,
                                                        MakePrototype(field.FieldType, targetPackage, compiler.Module));
                    method.AccessFlags = AccessFlags.Public | AccessFlags.Abstract;
                    result.FieldToGetMethodMap.Add(field, method);
                    @interface.Methods.Add(method);
                }

                // Add property mapping
                foreach (var property in currentType.Properties.Where(
                                              x => x.IsReachable && (x.SetMethod != null) 
                                         && x.SetMethod.IsPublic && x.SetMethod.IsReachable))
                {
                    // ignore properties with same name [might be overriden]
                    if (result.PropertyToGetMethodMap.Keys.Any(k => k.Name == property.Name))
                        continue;

                    string methodName = CreateGetMethodName(NameConverter.GetConvertedName(property), result);
                    Mono.Cecil.TypeReference propType = property.PropertyType;

                    MethodDefinition method = new MethodDefinition(@interface, methodName,
                                                        MakePrototype(propType, targetPackage, compiler.Module));
                    method.AccessFlags = AccessFlags.Public | AccessFlags.Abstract;
                    result.PropertyToGetMethodMap.Add(property, method);
                    @interface.Methods.Add(method);
                }

                if (currentType.BaseType == null || currentType.BaseType.IsSystemObject())
                    break;

                currentType = currentType.BaseType.Resolve();
            }
            // Add ctor mapping
            var argIndex = 0;
            foreach (var ctor in attributeType.Methods.Where(x => (x.Name == ".ctor") && x.IsReachable))
            {
                // Add methods for the ctor arguments
                List<Tuple<MethodDefinition, Mono.Cecil.TypeReference>> paramGetMethods = new List<Tuple<MethodDefinition, Mono.Cecil.TypeReference>>();
                foreach (ParameterDefinition p in ctor.Parameters)
                {
                    string methodName = CreateGetMethodName("c" + argIndex++, result);
                    MethodDefinition method = new MethodDefinition(@interface, methodName, MakePrototype(p.ParameterType, targetPackage, compiler.Module));
                    method.AccessFlags = AccessFlags.Public | AccessFlags.Abstract;
                    @interface.Methods.Add(method);
                    paramGetMethods.Add(Tuple.Create(method, p.ParameterType));
                }

                // Add a builder method
                MethodDefinition buildMethod = CreateBuildMethod(sequencePoint, ctor, paramGetMethods, compiler, targetPackage, attributeClass, result);
                result.CtorMap.Add(ctor, new AttributeCtorMapping(buildMethod, paramGetMethods.Select(p=>p.Item1).ToList()));
            }

            // Create default values annotation
            Annotation defAnnotation = CreateDefaultAnnotation(result);
            result.AnnotationInterfaceClass.Annotations.Add(defAnnotation);

            return result;
        }
        /// <summary>
        /// Create a method definition for the builder method that builds a custom attribute from an annotation.
        /// </summary>
        private static MethodDefinition CreateBuildMethod(
            ISourceLocation seqp,
            Mono.Cecil.MethodDefinition ctor,
            List<Tuple<MethodDefinition, Mono.Cecil.TypeReference>> paramGetMethods,
            AssemblyCompiler compiler,
            DexTargetPackage targetPackage,
            ClassDefinition attributeClass,
            AttributeAnnotationInterface mapping)
        {
            // Create method definition
            string name = CreateBuildMethodName(attributeClass);
            TypeReference attributeTypeRef = ctor.DeclaringType.GetReference(targetPackage, compiler.Module);
            MethodDefinition method = new MethodDefinition(attributeClass, name, new Prototype(attributeTypeRef, new Parameter(mapping.AnnotationInterfaceClass, "ann")));
            method.AccessFlags = AccessFlags.Public | AccessFlags.Static | AccessFlags.Synthetic;
            attributeClass.Methods.Add(method);

            // Create method body
            MethodBody body = new MethodBody(null);
            Register annotationReg = body.AllocateRegister(RCategory.Argument, RType.Object);
            //body.Instructions.Add(seqp, RCode.Check_cast, mapping.AnnotationInterfaceClass, annotationReg);

            // Allocate attribute
            Register attributeReg = body.AllocateRegister(RCategory.Temp, RType.Object);
            body.Instructions.Add(seqp, RCode.New_instance, attributeClass, attributeReg);

            // Get ctor arguments
            List<Register> ctorArgRegs = new List<Register>();
            foreach (var p in paramGetMethods)
            {
                Instruction branchIfNotSet; // this can not happen, but lets keep the code below simple.
                
                XModel.XTypeReference xType = XBuilder.AsTypeReference(compiler.Module, p.Item2);

                Register[] valueRegs = CreateLoadValueSequence(seqp, body, xType, annotationReg, p.Item1, compiler, targetPackage, out branchIfNotSet);
                branchIfNotSet.Operand = body.Instructions.Add(seqp, RCode.Nop);

                ctorArgRegs.AddRange(valueRegs);
            }

            // Invoke ctor
            DexLib.MethodReference dctor = ctor.GetReference(targetPackage, compiler.Module);
            body.Instructions.Add(seqp, RCode.Invoke_direct, dctor, new[] { attributeReg }.Concat(ctorArgRegs).ToArray());

            // Get field values
            foreach (var fieldMap in mapping.FieldToGetMethodMap)
            {
                var field = fieldMap.Key;
                XModel.XTypeReference xFieldType = XBuilder.AsTypeReference(compiler.Module, field.FieldType);
                
                MethodDefinition getter = fieldMap.Value;
                Instruction branchIfNotSet;
                
                Register[] valueRegs = CreateLoadValueSequence(seqp, body, xFieldType, annotationReg, getter, compiler, targetPackage, out branchIfNotSet);
              
                var put = body.Instructions.Add(seqp, xFieldType.IPut(), valueRegs[0], attributeReg);
                
                mapping.FixOperands.Add(Tuple.Create(put, (MemberReference)field));

                branchIfNotSet.Operand = body.Instructions.Add(seqp, RCode.Nop);
            }

            // Get property values
            foreach (var propertyMap in mapping.PropertyToGetMethodMap)
            {
                PropertyDefinition property = propertyMap.Key;
                XTypeReference xType = XBuilder.AsTypeReference(compiler.Module, property.PropertyType);

                MethodDefinition getter = propertyMap.Value;
                Instruction branchIfNotSet;

                Register[] valueRegs = CreateLoadValueSequence(seqp, body, xType, annotationReg, getter, compiler, targetPackage, out branchIfNotSet);
                
                XModel.XMethodDefinition xSetMethod = XBuilder.AsMethodDefinition(compiler.Module, property.SetMethod);
                
                var set = body.Instructions.Add(seqp, xSetMethod.Invoke(xSetMethod, null), null, new[] { attributeReg }.Concat(valueRegs).ToArray());

                mapping.FixOperands.Add(Tuple.Create(set, (MemberReference)property.SetMethod));

                branchIfNotSet.Operand = body.Instructions.Add(seqp, RCode.Nop);
            }

            // Return attribute
            body.Instructions.Add(seqp, RCode.Return_object, attributeReg);

            // Register method body
            targetPackage.Record(new CompiledMethod() { DexMethod = method, RLBody = body });

            // Return method
            return method;
        }
예제 #25
0
 public CacheEntry GetFromCache(MethodDefinition targetMethod, XMethodDefinition sourceMethod, AssemblyCompiler compiler, DexTargetPackage targetPackage)
 {
     var ret = GetFromCacheImpl(targetMethod, sourceMethod, compiler, targetPackage);
     
     if (ret != null) Interlocked.Increment(ref statCacheHits);
     else             Interlocked.Increment(ref statCacheMisses);
     
     return ret;
 }
 /// <summary>
 /// Create code to load a value from an annotation interface.
 /// </summary>
 /// <returns>The register(s) holding the value</returns>
 private static Register[] CreateLoadValueSequence(
     ISourceLocation seqp,
     MethodBody body,
     TypeReference valueType,
     Register annotationReg,
     MethodDefinition getter)
 {
     if (valueType.IsWide())
     {
         Tuple<Register, Register> regs = body.AllocateWideRegister(RCategory.Temp);
         body.Instructions.Add(seqp, RCode.Invoke_interface, getter, annotationReg);
         body.Instructions.Add(seqp, RCode.Move_result_wide, regs.Item1);
         return new[] { regs.Item1, regs.Item2 };
     }
     if (valueType is PrimitiveType)
     {
         Register reg = body.AllocateRegister(RCategory.Temp, RType.Value);
         body.Instructions.Add(seqp, RCode.Invoke_interface, getter, annotationReg);
         body.Instructions.Add(seqp, RCode.Move_result, reg);
         return new[] { reg };
     }
     else
     {
         Register reg = body.AllocateRegister(RCategory.Temp, RType.Object);
         body.Instructions.Add(seqp, RCode.Invoke_interface, getter, annotationReg);
         body.Instructions.Add(seqp, RCode.Move_result_object, reg);
         return new[] { reg };
     }
 }
        private MethodBody CreateCloneBody(MethodDefinition ctor, ClassDefinition @class)
        {
            MethodBody body = new MethodBody(null);
            var ins = body.Instructions;

            Register rthis       = body.AllocateRegister(RCategory.Argument, RType.Object);
            Register rInvList    = body.AllocateRegister(RCategory.Argument, RType.Object);
            Register rInvListLen = body.AllocateRegister(RCategory.Argument, RType.Value);

            Register result     = body.AllocateRegister(RCategory.Temp, RType.Object);

            List<Register> ctorArgs = new List<Register> { result };

            if (instanceField != null)
            {
                var rInstance = body.AllocateRegister(RCategory.Temp, RType.Object);
                ins.Add(new Instruction(RCode.Iget_object, instanceField, new[] {rInstance, rthis}));
                ctorArgs.Add(rInstance);
            }

            foreach (var field in GenericTypeFields)
            {
                var r = body.AllocateRegister(RCategory.Temp, RType.Object);
                ins.Add(new Instruction(RCode.Iget_object, field, new[] { r, rthis }));
                ctorArgs.Add(r);
            }

            ins.Add(new Instruction(RCode.New_instance, @class, new[] {result}));
            ins.Add(new Instruction(RCode.Invoke_direct, ctor, ctorArgs.ToArray()));

            var invListLengthReference = new FieldReference(multicastDelegateClass, "InvocationListLength", PrimitiveType.Int);
            var multicastDelegateArray = new ArrayType(multicastDelegateClass);
            var invListReference = new FieldReference(multicastDelegateClass, "InvocationList", multicastDelegateArray);

            ins.Add(new Instruction(RCode.Iput_object, invListReference, new []{ rInvList, result}));
            ins.Add(new Instruction(RCode.Iput, invListLengthReference, new[] { rInvListLen, result }));
            
            ins.Add(new Instruction(RCode.Return_object, null, new []{result}));
            return body;
        }
        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);            
        }
        /// <summary>
        /// Create an annotation interface.
        /// </summary>
        internal static AttributeAnnotationInterface Create(
            ISourceLocation sequencePoint,
            AssemblyCompiler compiler,
            DexTargetPackage targetPackage,
            TypeDefinition attributeType,
            ClassDefinition attributeClass)
        {
            // Create class
            ClassDefinition @interface = new ClassDefinition();
            @interface.Name = CreateAnnotationTypeName(attributeClass);
            @interface.Namespace = attributeClass.Namespace;
            @interface.AccessFlags = AccessFlags.Public | AccessFlags.Abstract | AccessFlags.Interface | AccessFlags.Annotation;
            @interface.Owner = attributeClass;
            attributeClass.InnerClasses.Add(@interface);

            // Set super class
            @interface.SuperClass = new ClassReference("java/lang/Object");

            // Implement Dot42.Internal.IAttribute
            @interface.Interfaces.Add(new ClassReference("java/lang/annotation/Annotation"));

            // Prepare result
            AttributeAnnotationInterface result = new AttributeAnnotationInterface(@interface);

            // Add methods from IAttribute
            XModel.XTypeDefinition baseIntfType = compiler.GetDot42InternalType("IAttribute").Resolve();
            foreach (XModel.XMethodDefinition imethod in baseIntfType.Methods)
            {
                if (imethod.Parameters.Count > 0) 
                    throw new CompilerException(string.Format("Invalid IAttribute method {0}", imethod));
                string methodName = NameConverter.GetConvertedName(imethod);
                TypeReference dfieldType = imethod.ReturnType.GetReference(targetPackage);
                MethodDefinition method = new MethodDefinition(@interface, methodName, new Prototype(dfieldType));
                method.AccessFlags = AccessFlags.Public | AccessFlags.Abstract;
                @interface.Methods.Add(method);                
            }

            // Add field mapping
            foreach (var field in attributeType.Fields.Where(x => x.IsReachable && x.IsPublic))
            {
                string methodName = CreateGetMethodName(NameConverter.GetConvertedName(field), result);
                TypeReference dfieldType = field.FieldType.GetReference(targetPackage, compiler.Module);
                MethodDefinition method = new MethodDefinition(@interface, methodName, new Prototype(dfieldType));
                method.AccessFlags = AccessFlags.Public | AccessFlags.Abstract;
                result.FieldToGetMethodMap.Add(field, method);
                @interface.Methods.Add(method);
            }

            // Add property mapping
            foreach (var property in attributeType.Properties.Where(x => x.IsReachable && (x.SetMethod != null) && (x.SetMethod.IsPublic) && x.SetMethod.IsReachable))
            {
                string methodName = CreateGetMethodName(NameConverter.GetConvertedName(property), result);
                TypeReference dpropType = property.PropertyType.GetReference(targetPackage, compiler.Module);
                MethodDefinition method = new MethodDefinition(@interface, methodName, new Prototype(dpropType));
                method.AccessFlags = AccessFlags.Public | AccessFlags.Abstract;
                result.PropertyToGetMethodMap.Add(property, method);
                @interface.Methods.Add(method);
            }

            // Add ctor mapping
            var argIndex = 0;
            foreach (var ctor in attributeType.Methods.Where(x => (x.Name == ".ctor") && x.IsReachable))
            {
                // Add methods for the ctor arguments
                List<MethodDefinition> paramGetMethods = new List<MethodDefinition>();
                foreach (ParameterDefinition p in ctor.Parameters)
                {
                    string methodName = CreateGetMethodName("c" + argIndex++, result);
                    TypeReference dparamType = p.ParameterType.GetReference(targetPackage, compiler.Module);
                    MethodDefinition method = new MethodDefinition(@interface, methodName, new Prototype(dparamType));
                    method.AccessFlags = AccessFlags.Public | AccessFlags.Abstract;
                    @interface.Methods.Add(method);
                    paramGetMethods.Add(method);
                }

                // Add a builder method
                MethodDefinition buildMethod = CreateBuildMethod(sequencePoint, ctor, paramGetMethods, compiler, targetPackage, attributeClass, result);
                result.CtorMap.Add(ctor, new AttributeCtorMapping(buildMethod, paramGetMethods));
            }

            // Create default values annotation
            Annotation defAnnotation = CreateDefaultAnnotation(result);
            result.AnnotationInterfaceClass.Annotations.Add(defAnnotation);

            return result;
        }
        public CacheEntry GetFromCacheImpl(MethodDefinition targetMethod, XMethodDefinition sourceMethod, AssemblyCompiler compiler, DexTargetPackage targetPackage)
        {
            if (_initialize == null)
            {
                return(null);
            }
            _initialize.Wait();

            if (!IsEnabled)
            {
                return(null);
            }

            if (sourceMethod.ScopeId == null || sourceMethod.ScopeId == "(none)")
            {
                return(null);
            }

            if (IsUnderlyingCodeModified(sourceMethod))
            {
                return(null);
            }

            Tuple <TypeEntry, MethodEntry> entry;

            string typeScopeId   = sourceMethod.DeclaringType.ScopeId;
            string methodScopeId = sourceMethod.ScopeId;

            MethodDefinition cachedMethod;

            if (_methodsByScopeId.TryGetValue(Tuple.Create(typeScopeId, methodScopeId), out entry))
            {
                cachedMethod = _dexLookup.GetMethod(entry.Item1.DexName, entry.Item2.DexName, entry.Item2.DexSignature);
            }
            else
            {
                // try directly in the dexlookup, for jar imports
                cachedMethod = _dexLookup.GetMethod(typeScopeId.Replace("/", "."), targetMethod.Name, targetMethod.Prototype.ToSignature());
            }

            if (cachedMethod == null)
            {
                return(null);
            }

            if (cachedMethod.Body == null)
            {
                // I believe there is a bug in MethodExplicitInterfaceConverter generating
                // stubs for interfaces if they derive from an imported interface.
                // Bail out for now until this is fixed.
                DLog.Debug(DContext.CompilerCodeGenerator, "Compiler cache: no method body found on cached version of {0}, even though one was expected.", sourceMethod);
                return(null);
            }

            try
            {
                if (!Equals(cachedMethod.Prototype, targetMethod.Prototype))
                {
                    throw new Exception("internal error, got the wrong method.");
                }

                var body = DexMethodBodyCloner.Clone(targetMethod, cachedMethod);
                FixReferences(body, compiler, targetPackage);

                string className = entry != null ? entry.Item1.DexName : body.Owner.Owner.Fullname;
                var    @class    = _dexLookup.GetClass(className);

                return(new CacheEntry(body, entry != null ? entry.Item2 : null, entry != null ? _map.GetSourceCodePositions(entry.Item2) : null, @class.SourceFile));
            }
            catch (CompilerCacheResolveException ex)
            {
                // This happens at the moment for methods using fields in the __generated class,
                // as well as for references to generated methods (mostly explicit interfac stubs)
                // during the IL conversion phase.
                // This also seems to happen for Framework-nested classes, maybe because these do
                // not get an entry in the map file. This should be fixed.
                // The number of these failures in my test is 890 out of ~12000. We gracefully
                // handle errors by re-compiling the method body.
                Debug.WriteLine(string.Format("Compiler cache: error while converting cached body: {0}: {1}. Not using cached body.", sourceMethod, ex.Message));
                return(null);
            }
            catch (Exception ex)
            {
                DLog.Warning(DContext.CompilerCodeGenerator, "Compiler cache: exception while converting cached body: {0}: {1}. Not using cached body.", sourceMethod, ex.Message);
                Trace.WriteLine(string.Format("Compiler cache: error while converting cached body: {0}: {1}. Not using cached body.", sourceMethod, ex.Message));
                return(null);
            }
        }
예제 #31
0
        public CacheEntry GetFromCacheImpl(MethodDefinition targetMethod, XMethodDefinition sourceMethod, AssemblyCompiler compiler, DexTargetPackage targetPackage)
        {
            if (_initialize == null)
                return null;
            _initialize.Wait();

            if (!IsEnabled)
                return null;

            if (sourceMethod.ScopeId == null || sourceMethod.ScopeId == "(none)")
            {
                return null;
            }

            if (IsUnderlyingCodeModified(sourceMethod)) 
                return null;

            Tuple<TypeEntry, MethodEntry> entry;

            string typeScopeId = sourceMethod.DeclaringType.ScopeId;
            string methodScopeId = sourceMethod.ScopeId;

            MethodDefinition cachedMethod;

            if (_methodsByScopeId.TryGetValue(Tuple.Create(typeScopeId, methodScopeId), out entry))
            {
                cachedMethod = _dexLookup.GetMethod(entry.Item1.DexName, entry.Item2.DexName, entry.Item2.DexSignature);
            }
            else
            {
                // try directly in the dexlookup, for jar imports
                cachedMethod = _dexLookup.GetMethod(typeScopeId.Replace("/", "."), targetMethod.Name, targetMethod.Prototype.ToSignature());
            }

            if (cachedMethod == null)
                return null;

            if (cachedMethod.Body == null)
            {
                // I believe there is a bug in MethodExplicitInterfaceConverter generating
                // stubs for interfaces if they derive from an imported interface.
                // Bail out for now until this is fixed.
                DLog.Debug(DContext.CompilerCodeGenerator, "Compiler cache: no method body found on cached version of {0}, even though one was expected.", sourceMethod);
                return null;
            }

            try
            {
                if (!Equals(cachedMethod.Prototype,targetMethod.Prototype))
                {
                    throw new Exception("internal error, got the wrong method.");
                }

                var body = DexMethodBodyCloner.Clone(targetMethod, cachedMethod);
                FixReferences(body, compiler, targetPackage);

                string className = entry != null ? entry.Item1.DexName : body.Owner.Owner.Fullname;
                var @class = _dexLookup.GetClass(className);

                return new CacheEntry(body, entry != null ? entry.Item2 : null, entry != null ? _map.GetSourceCodePositions(entry.Item2) : null, @class.SourceFile);
            }
            catch (CompilerCacheResolveException ex)
            {
                // This happens at the moment for methods using fields in the __generated class,
                // as well as for references to generated methods (mostly explicit interfac stubs)
                // during the IL conversion phase.
                // This also seems to happen for Framework-nested classes, maybe because these do
                // not get an entry in the map file. This should be fixed.
                // The number of these failures in my test is 890 out of ~12000. We gracefully
                // handle errors by re-compiling the method body.
                Debug.WriteLine(string.Format("Compiler cache: error while converting cached body: {0}: {1}. Not using cached body.", sourceMethod, ex.Message));
                return null;
            }
            catch (Exception ex)
            {
                DLog.Warning(DContext.CompilerCodeGenerator, "Compiler cache: exception while converting cached body: {0}: {1}. Not using cached body.", sourceMethod, ex.Message);
                Trace.WriteLine(string.Format("Compiler cache: error while converting cached body: {0}: {1}. Not using cached body.", sourceMethod, ex.Message));
                return null;
            }
        }
        private static MethodDefinition CreateFactoryMethod(AssemblyCompiler compiler, DexTargetPackage targetPackage, CustomAttribute attribute, AttributeAnnotationMapping mapping)
        {
            var targetClass = mapping.AttributeClass; // is this really the right place for the factory methods?
            ISourceLocation seqp = null;
            var attributeTypeDef = attribute.AttributeType.Resolve();

            // create method
            string methodName = CreateAttributeFactoryMethodName(targetClass); 
            MethodDefinition method = new MethodDefinition(targetClass, methodName, new Prototype(mapping.AttributeClass));
            method.AccessFlags = AccessFlags.Public | AccessFlags.Static | AccessFlags.Synthetic;
            targetClass.Methods.Add(method);

            // create method body
            MethodBody body = new MethodBody(null);
            // Allocate attribute
            Register attributeReg = body.AllocateRegister(RCategory.Temp, RType.Object);
            body.Instructions.Add(seqp, RCode.New_instance, mapping.AttributeClass, attributeReg);

            // collect ctor arguments
            List<Register> ctorArgRegs = new List<Register>() { attributeReg };
            foreach (var p in attribute.ConstructorArguments)
            {
                XTypeReference xType = XBuilder.AsTypeReference(compiler.Module, p.Type);
                Register[] valueRegs = CreateInitializeValueInstructions(seqp, body, xType, p, compiler, targetPackage);
                ctorArgRegs.AddRange(valueRegs);
            }
            // Invoke ctor
            DexLib.MethodReference dctor = attribute.Constructor.GetReference(targetPackage, compiler.Module);
            body.Instructions.Add(seqp, RCode.Invoke_direct, dctor, ctorArgRegs.ToArray());

            // set field values
            foreach (var p in attribute.Fields)
            {
                var field = GetField(attributeTypeDef, p.Name);
                var xField = XBuilder.AsFieldReference(compiler.Module, field);

                Register[] valueRegs = CreateInitializeValueInstructions(seqp, body, xField.FieldType, p.Argument, compiler, targetPackage);
                body.Instructions.Add(seqp, xField.FieldType.IPut(), xField.GetReference(targetPackage),
                                                valueRegs[0], attributeReg);
            }

            // set property values
            foreach (var p in attribute.Properties)
            {
                PropertyDefinition property = GetSettableProperty(attributeTypeDef, p.Name);
                XTypeReference xType = XBuilder.AsTypeReference(compiler.Module, property.PropertyType);

                Register[] valueRegs = CreateInitializeValueInstructions(seqp, body, xType, p.Argument, compiler, targetPackage);
                XMethodDefinition xSetMethod = XBuilder.AsMethodDefinition(compiler.Module, property.SetMethod);
                body.Instructions.Add(seqp, xSetMethod.Invoke(xSetMethod, null), 
                                            xSetMethod.GetReference(targetPackage), 
                                            new[] { attributeReg }.Concat(valueRegs).ToArray());
            }

            // Return attribute
            body.Instructions.Add(seqp, RCode.Return_object, attributeReg);

            // Register method body
            targetPackage.Record(new CompiledMethod() { DexMethod = method, RLBody = body });

            // Return method
            return method;

        }
        /// <summary>
        /// Create code to load a value from an annotation interface.
        /// </summary>
        /// <returns>The register(s) holding the value</returns>
        private static Register[] CreateLoadValueSequence(
            ISourceLocation seqp,
            MethodBody body,
            XTypeReference valueType,
            Register annotationReg,
            MethodDefinition getter,
            AssemblyCompiler compiler,
            DexTargetPackage targetPackage,
            out Instruction branchIfNotSet)
        {
            // NOTE: It would be better if we wouldn't get the values as object arrays
            //       but as arrays of the actual type. 
            //       Apparently though the DexWriter will not write our attributes
            //       if they contain arrays not of type object[]. Therefore the 
            //       conversion code below.
            //       All in all it would be much cleaner if we could emit Ast code here
            //       instead of RL code.
            List<Register> result = new List<Register>();

            // get the array.
            Register regObject = body.AllocateRegister(RCategory.Temp, RType.Object);
            Register regIntVal = body.AllocateRegister(RCategory.Temp, RType.Value);
            
            body.Instructions.Add(seqp, RCode.Invoke_interface, getter, annotationReg);
            body.Instructions.Add(seqp, RCode.Move_result_object, regObject);

            // allocate result, initialize to default value.
            if (valueType.IsWide())
            {
                Tuple<Register, Register> regs = body.AllocateWideRegister(RCategory.Temp);
                body.Instructions.Add(seqp, RCode.Const_wide, 0, regs.Item1);
                result.Add(regs.Item1);
                result.Add(regs.Item2);
            }
            else if (valueType.IsPrimitive)
            {
                Register reg = body.AllocateRegister(RCategory.Temp, RType.Value);
                body.Instructions.Add(seqp, RCode.Const, 0, reg);
                result.Add(reg);
            }
            else // object 
            {
                Register reg = body.AllocateRegister(RCategory.Temp, RType.Object);
                body.Instructions.Add(seqp, RCode.Const, 0, reg);
                result.Add(reg);
            }

            // check if value is unset (array length 0) or null (array length 2)
            body.Instructions.Add(seqp, RCode.Array_length, regIntVal, regObject);
            branchIfNotSet = body.Instructions.Add(seqp, RCode.If_eqz, regIntVal);
            body.Instructions.Add(seqp, RCode.Rsub_int, 1, regIntVal, regIntVal);
            var branchOnNull = body.Instructions.Add(seqp, RCode.If_nez, regIntVal);

            // get the (boxed) value
            body.Instructions.Add(seqp, RCode.Const, 0, regIntVal);

            // convert to target type.
            if (valueType.IsArray)
            {
                Register regTmp = body.AllocateRegister(RCategory.Temp, RType.Object);
                Register regType = body.AllocateRegister(RCategory.Temp, RType.Object);
                
                var helper = compiler.GetDot42InternalType(InternalConstants.CompilerHelperName);
                var convertArray = helper.Resolve().Methods.First(p => p.Name == "ConvertArray" && p.Parameters.Count == 2)
                                         .GetReference(targetPackage);
                var underlying = valueType.ElementType.GetReference(targetPackage);

                body.Instructions.Add(seqp, RCode.Aget_object, regTmp, regObject, regIntVal);
                body.Instructions.Add(seqp, RCode.Const_class, underlying, regType);
                body.Instructions.Add(seqp, RCode.Invoke_static, convertArray, regTmp, regType);
                body.Instructions.Add(seqp, RCode.Move_result_object, result[0]);
                body.Instructions.Add(seqp, RCode.Check_cast, valueType.GetReference(targetPackage), result[0]);
            }
            else if (valueType.IsEnum())
            {
                Register regTmp = body.AllocateRegister(RCategory.Temp, RType.Object);
                Register regType = body.AllocateRegister(RCategory.Temp, RType.Object);
                
                var getFromObject = compiler.GetDot42InternalType("Enum").Resolve()
                                            .Methods.Single(p=>p.Name == "GetFromObject")
                                            .GetReference(targetPackage);

                body.Instructions.Add(seqp, RCode.Aget_object, regTmp, regObject, regIntVal);
                body.Instructions.Add(seqp, RCode.Const_class, valueType.GetReference(targetPackage), regType);
                body.Instructions.Add(seqp, RCode.Invoke_static, getFromObject, regType, regTmp);
                body.Instructions.Add(seqp, valueType.MoveResult(), result[0]);
                body.Instructions.Add(seqp, RCode.Check_cast, valueType.GetReference(targetPackage), result[0]);
            }
            else if(!valueType.IsPrimitive)
            {
                body.Instructions.Add(seqp, RCode.Aget_object, result[0], regObject, regIntVal);
                body.Instructions.Add(seqp, RCode.Check_cast, valueType.GetReference(targetPackage), result[0]);
            }
            else
            {
                Register regTmp = body.AllocateRegister(RCategory.Temp, RType.Object);
                // unbox and store
                RCode afterConvert;
                var unbox  = valueType.GetUnboxValueMethod(compiler, targetPackage, out afterConvert);
                body.Instructions.Add(seqp, RCode.Aget_object, regTmp, regObject, regIntVal);
                body.Instructions.Add(seqp, RCode.Invoke_static, unbox, regTmp);
                body.Instructions.Add(seqp, valueType.MoveResult(), result[0]);
                
                if (afterConvert != RCode.Nop)
                {
                    body.Instructions.Add(seqp, afterConvert, result[0], result[0]);
                }
            }

            // nop will be removed at some stage later.
            var nop = body.Instructions.Add(seqp, RCode.Nop);
            branchOnNull.Operand = nop;

            return result.ToArray();
        }
예제 #34
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);

        }
예제 #35
0
 /// <summary>
 /// Default ctor
 /// </summary>
 public DelegateInstanceType(XMethodDefinition calledMethod, ClassDefinition instanceDefinition, Dot42.DexLib.MethodDefinition instanceCtor)
 {
     this.calledMethod       = calledMethod;
     this.instanceDefinition = instanceDefinition;
     this.instanceCtor       = instanceCtor;
 }
예제 #36
0
        /// <summary>
        /// Create a method definition for the builder method that builds a custom attribute from an annotation.
        /// </summary>
        private static MethodDefinition CreateBuildMethod(
            ISourceLocation seqp,
            Mono.Cecil.MethodDefinition ctor,
            List <MethodDefinition> paramGetMethods,
            AssemblyCompiler compiler,
            DexTargetPackage targetPackage,
            ClassDefinition attributeClass,
            AttributeAnnotationInterface mapping)
        {
            // Create method definition
            string           name             = CreateBuildMethodName(attributeClass);
            TypeReference    attributeTypeRef = ctor.DeclaringType.GetReference(targetPackage, compiler.Module);
            MethodDefinition method           = new MethodDefinition(attributeClass, name, new Prototype(attributeTypeRef, new Parameter(mapping.AnnotationInterfaceClass, "ann")));

            method.AccessFlags = AccessFlags.Public | AccessFlags.Static | AccessFlags.Synthetic;
            attributeClass.Methods.Add(method);

            // Create method body
            MethodBody body          = new MethodBody(null);
            Register   annotationReg = body.AllocateRegister(RCategory.Argument, RType.Object);
            //body.Instructions.Add(seqp, RCode.Check_cast, mapping.AnnotationInterfaceClass, annotationReg);

            // Allocate attribute
            Register attributeReg = body.AllocateRegister(RCategory.Temp, RType.Object);

            body.Instructions.Add(seqp, RCode.New_instance, attributeClass, attributeReg);

            // Get ctor arguments
            List <Register> ctorArgRegs = new List <Register>();

            foreach (MethodDefinition p in paramGetMethods)
            {
                TypeReference paramType = p.Prototype.ReturnType;
                Register[]    valueRegs = CreateLoadValueSequence(seqp, body, paramType, annotationReg, p);
                ctorArgRegs.AddRange(valueRegs);
            }

            // Invoke ctor
            DexLib.MethodReference dctor = ctor.GetReference(targetPackage, compiler.Module);
            body.Instructions.Add(seqp, RCode.Invoke_direct, dctor, new[] { attributeReg }.Concat(ctorArgRegs).ToArray());

            // Get field values
            foreach (var fieldMap in mapping.FieldToGetMethodMap)
            {
                Mono.Cecil.FieldDefinition field  = fieldMap.Key;
                MethodDefinition           getter = fieldMap.Value;
                Register[]            valueRegs   = CreateLoadValueSequence(seqp, body, getter.Prototype.ReturnType, annotationReg, getter);
                DexLib.FieldReference dfield      = field.GetReference(targetPackage, compiler.Module);
                XModel.XTypeReference xFieldType  = XBuilder.AsTypeReference(compiler.Module, field.FieldType);
                body.Instructions.Add(seqp, xFieldType.IPut(), dfield, valueRegs[0], attributeReg);
            }

            // Get property values
            foreach (var propertyMap in mapping.PropertyToGetMethodMap)
            {
                PropertyDefinition       property   = propertyMap.Key;
                MethodDefinition         getter     = propertyMap.Value;
                Register[]               valueRegs  = CreateLoadValueSequence(seqp, body, getter.Prototype.ReturnType, annotationReg, getter);
                DexLib.MethodReference   dmethod    = property.SetMethod.GetReference(targetPackage, compiler.Module);
                XModel.XMethodDefinition xSetMethod = XBuilder.AsMethodDefinition(compiler.Module, property.SetMethod);
                body.Instructions.Add(seqp, xSetMethod.Invoke(xSetMethod, null), dmethod, new[] { attributeReg }.Concat(valueRegs).ToArray());
            }

            // Return attribute
            body.Instructions.Add(seqp, RCode.Return_object, attributeReg);

            // Register method body
            targetPackage.Record(new CompiledMethod()
            {
                DexMethod = method, RLBody = body
            });

            // Return method
            return(method);
        }
예제 #37
0
 /// <summary>
 /// Default ctor
 /// </summary>
 public DexMethodDefinitionNode(MethodDefinition methodDef)
 {
     this._methodDef = methodDef;
     Text = methodDef.Name;
     ImageIndex = 6;
 }
 private void AddMethod(ClassDefinition @class, string methodName, Prototype prototype, AccessFlags accessFlags, MethodBody body)
 {
     var method = new MethodDefinition(@class, methodName, prototype);
     method.AccessFlags = accessFlags;
     @class.Methods.Add(method);
     targetPackage.Record(new CompiledMethod { DexMethod = method, RLBody = body});
 }
예제 #39
0
 /// <summary>
 /// Default ctor
 /// </summary>
 public DelegateInstanceType(XMethodDefinition calledMethod, ClassDefinition instanceDefinition, Dot42.DexLib.MethodDefinition instanceCtor)
 {
     this.calledMethod = calledMethod;
     this.instanceDefinition = instanceDefinition;
     this.instanceCtor = instanceCtor;
 }
        /// <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));
        }