Beispiel #1
0
        /// <summary>
        /// Convert the given method into optimized Ast format.
        /// </summary>
        internal protected static AstNode CreateOptimizedAst(AssemblyCompiler compiler, MethodSource source,
            bool generateSetNextInstructionCode, 
            StopAstConversion debugStop = StopAstConversion.None,
            AstOptimizationStep debugStopOptimizing = AstOptimizationStep.None
            )
        {
            // Build AST
            DecompilerContext context;
            AstBlock ast;
            if (source.IsDotNet)
            {
                context = new DecompilerContext(source.Method);
                var astBuilder = new IL2Ast.AstBuilder(source.ILMethod, true, context);
                var children = astBuilder.Build();
                ast = new AstBlock(children.Select(x => x.SourceLocation).FirstOrDefault(), children);
                if ((source.ILMethod.IsConstructor) && (source.Method.DeclaringType.Fields.Any(x => x.FieldType.IsEnum() || x.Name.EndsWith(NameConstants.Atomic.FieldUpdaterPostfix))))
                {
                    // Ensure all fields are initialized
                    AddFieldInitializationCode(compiler, source, ast);
                }
                if (source.Method.NeedsGenericInstanceTypeParameter && (source.Name == ".ctor"))
                {
                    // Add code to save the generic instance type parameter into the generic instance field.
                    AddGenericInstanceFieldInitializationCode(source, ast, compiler.Module.TypeSystem);
                }
            }
            else if (source.IsJava)
            {
                var astBuilder = new Java2Ast.AstBuilder(compiler.Module, source.JavaMethod, source.Method.DeclaringType, true);
                context = new DecompilerContext(source.Method);
                ast = astBuilder.Build();
            }
            else if (source.IsAst)
            {
                context = new DecompilerContext(source.Method);
                ast = source.Ast;
            }
            else
            {
                throw new NotSupportedException("Unknown source");
            }

            if (debugStop == StopAstConversion.AfterILConversion) return ast;

            // Optimize AST
            var astOptimizer = new AstOptimizer(context, ast);
            astOptimizer.Optimize(debugStopOptimizing);

            if (debugStop == StopAstConversion.AfterOptimizing) return ast;

            // Optimize AST towards the target
            TargetConverters.Convert(context, ast, source, compiler, debugStop);

            if(generateSetNextInstructionCode)
                SetNextInstructionGenerator.Convert(ast, source, compiler);

            // Return return
            return ast;
        }
        public static void Convert(AstNode ast, MethodSource currentMethod, AssemblyCompiler compiler)
        {
            foreach (var block in ast.GetSelfAndChildrenRecursive<AstBlock>())
            {
                for (int i = 0; i < block.Body.Count; ++i)
                {
                    var expr = block.Body[i] as AstExpression;
                    if(expr == null) 
                        continue;


                    var interlockedPairs = expr.GetExpressionPairs(p =>
                                            p.Code == AstCode.Call
                                            && ((XMethodReference) p.Operand).DeclaringType.FullName == "System.Threading.Interlocked")
                                            .ToList();
                                                    
                    if(interlockedPairs.Count == 0) 
                        continue;
                    if (interlockedPairs.Count > 1)
                        throw new CompilerException("The Interlocked converter can not handle more than one interlocked call per statement. Try splittig the statement up.");

                    var interlockedCall = interlockedPairs.First().Expression;

                    // first parameter should be a reference to a field,
                    // (but be lenient if we don't find what we expect)
                    
                    var targetExpr = interlockedCall.Arguments[0];

                    XFieldReference field = null;

                    if (targetExpr.InferredType.IsByReference)
                    {
                        field = targetExpr.Operand as XFieldReference;

                        if (field != null)
                        {
                            // check if we have an atomic updater 
                            var updater = field.DeclaringType.Resolve().Fields
                                                             .FirstOrDefault(f => f.Name == field.Name + NameConstants.Atomic.FieldUpdaterPostfix);
                            if (updater != null)
                            {
                                var method = (XMethodReference) interlockedCall.Operand;
                                var methodName = method.Name.Split('$')[0]; // retrieve original name.

                                if (InterlockedUsingUpdater(interlockedCall, methodName, field, updater, targetExpr, interlockedPairs.First().Parent, compiler))
                                    continue;
                            }
                        }
                    }
                    

                    FailsafeInterlockedUsingLocking(field, expr, targetExpr, block, i, compiler, currentMethod);
                }

            }
        }
Beispiel #3
0
 /// <summary>
 /// Optimize expressions
 /// </summary>
 public static void Convert(AstNode ast, MethodSource currentMethod, XTypeSystem typeSystem)
 {
     // Expand typeof
     foreach (var pair in ast.GetExpressionPairs())
     {
         var node = pair.Expression;
         switch (node.Code)
         {
             case AstCode.Ldfld:
             //case AstCode.Ldsfld: // NOT YET
                 {
                     var field = (XFieldReference) node.Operand;
                     UnboxIfGeneric(field.FieldType, node, typeSystem);
                 }
                 break;
             case AstCode.Stfld:
                 {
                     var field = (XFieldReference)node.Operand;
                     BoxIfGeneric(field.FieldType, node.Arguments[1]);
                 }
                 break;
             case AstCode.Call:
             case AstCode.Calli:
             case AstCode.Callvirt:
                 {
                     var method = (XMethodReference)node.Operand;
                     if ((!method.ReturnType.IsVoid()) && (pair.Parent != null))
                     {
                         UnboxIfGeneric(method.ReturnType, node, typeSystem);
                     }
                 }
                 break;
             case AstCode.Ret:
                 {
                     if (node.Arguments.Count > 0)
                     {
                         var expectedType = currentMethod.Method.ReturnType;
                         BoxIfGeneric(expectedType, node.Arguments[0]);
                     }
                 }
                 break;
             case AstCode.ByRefArray:
             case AstCode.ByRefOutArray:
             {
                 if (node.Arguments.Count > 1)
                 {
                     var originalType = (XTypeReference) node.Arguments[1].Operand;
                     UnboxByRefIfGeneric(originalType, node.StoreByRefExpression, typeSystem);
                 }
             }
             break;
         }
     }
 }
        public static void Convert(AstNode ast, MethodSource currentMethod, AssemblyCompiler compiler)
        {
            // only work on MoveNext of IAsyncStateMachine implementations.
            if (currentMethod.Name != "MoveNext" && currentMethod.Name != "IAsyncStateMachine_MoveNext")
                return;
            var declaringType = currentMethod.Method.DeclaringType.Resolve();
            if (declaringType.Interfaces.All(i => i.FullName != "System.Runtime.CompilerServices.IAsyncStateMachine"))
                return;

            foreach(var block in ast.GetSelfAndChildrenRecursive<AstBlock>())
                FixBlock(block);
        }
Beispiel #5
0
        public SourceLocation(MethodSource source, SourceFile file, int line, int column)
            : this(new DynamicSourceLocation (source, file, line, column))
        {
            Module = file.Module.Name;
            FileName = file.FileName;
            Method = source.Name;

            if (line != -1)
                Name = source.Name + ':' + line;
            else
                Name = source.Name;

            Line = line;
            Column = column;
        }
Beispiel #6
0
        /// <summary>
        /// Convert the given method into optimized Ast format.
        /// </summary>
        protected static AstNode CreateOptimizedAst(AssemblyCompiler compiler, MethodSource source)
        {
            // Build AST
            DecompilerContext context;
            AstBlock ast;
            if (source.IsDotNet)
            {
                context = new DecompilerContext(source.Method);
                var astBuilder = new IL2Ast.AstBuilder(source.ILMethod, true, context);
                var children = astBuilder.Build();
                ast = new AstBlock(children.Select(x => x.SourceLocation).FirstOrDefault(), children);
                if ((source.ILMethod.IsConstructor) && (source.Method.DeclaringType.Fields.Any(x => x.FieldType.IsEnum())))
                {
                    // Ensure all fields are initialized
                    AddFieldInitializationCode(source, ast);
                }
                if (source.Method.NeedsGenericInstanceTypeParameter && (source.Name == ".ctor"))
                {
                    // Add code to safe the generic instance type parameter into the generic instance field.
                    AddGenericInstanceFieldInitializationCode(ast);
                }
            }
            else if (source.IsJava)
            {
                var astBuilder = new Java2Ast.AstBuilder(compiler.Module, source.JavaMethod, source.Method.DeclaringType, true);
                context = new DecompilerContext(source.Method);
                ast = astBuilder.Build();
            }
            else if (source.IsAst)
            {
                context = new DecompilerContext(source.Method);
                ast = source.Ast;
            }
            else
            {
                throw new NotSupportedException("Unknown source");
            }

            // Optimize AST
            var astOptimizer = new AstOptimizer(context, ast);
            astOptimizer.Optimize();

            // Optimize AST towards the target
            TargetConverters.Convert(context, ast, source, compiler);

            // Return return
            return ast;
        }
        /// <summary>
        /// Compile this method to dex code.
        /// </summary>
        public void Compile(AssemblyCompiler compiler, DexTargetPackage targetPackage)
        {
            if (Body == null)
            {
                throw new ArgumentException("Body expected");
            }
            if (dexMethod == null)
            {
                throw new ArgumentException("dexMethod expected");
            }
            CompiledMethod compiledMethod;
            var            source = new MethodSource(this, Body);

            DexMethodBodyCompiler.TranslateToRL(compiler, targetPackage, source, dexMethod, out compiledMethod);
            compiledMethod.DexMethod = dexMethod;
        }
Beispiel #8
0
        /// <summary>
        /// Perform all dot42 related Ast conversions.
        /// </summary>
        public static void Convert(DecompilerContext context, AstBlock ast, MethodSource currentMethod, AssemblyCompiler compiler)
        {
            if (ast.IsOptimizedForTarget)
            {
                return;
            }
#if DEBUG
            //Debugger.Launch();
            if ((currentMethod.Method != null) && (currentMethod.Method.Name.Equals("runTest", StringComparison.OrdinalIgnoreCase)))
            {
                //Debugger.Launch();
            }
#endif

            IntPtrConverter.Convert(ast, compiler);
            TypeOfConverter.Convert(ast, compiler);
            BranchOptimizer.Convert(ast);
            CompoundAssignmentConverter.Convert(ast);
            ByReferenceParamConverter.Convert(context, ast, compiler);
            CompareUnorderedConverter.Convert(ast);
            EnumConverter.Convert(ast, compiler);
            EnumOptimizer.Convert(ast, compiler);

            // Keep this order
            NullableConverter.Convert(ast, compiler);
            PrimitiveAddressOfConverter.Convert(ast, currentMethod, compiler);
            StructCallConverter.Convert(ast, compiler);
            // end

            InitializeStructVariablesConverter.Convert(ast);
            DelegateConverter.Convert(ast);
            LdcWideConverter.Convert(ast);
            LdLocWithConversionConverter.Convert(ast);
            ConvertAfterLoadConversionConverter.Convert(ast);
            ConvertBeforeStoreConversionConverter.Convert(ast);
            CleanupConverter.Convert(ast);

            GenericsConverter.Convert(ast);

            // Expand cast expressions
            CastConverter.Convert(ast, currentMethod, compiler);

            // Expand generic instance information
            GenericInstanceConverter.Convert(ast, currentMethod, compiler);
        }
Beispiel #9
0
 /// <summary>
 /// Validates this object and throws a <see cref="NotSupportedException"/> in
 /// the case of an unsupported kernel configuration.
 /// </summary>
 public void Validate()
 {
     if (MethodSource == null)
     {
         throw new NotSupportedException(
                   ErrorMessages.InvalidEntryPointWithoutDotNetMethod);
     }
     if (!MethodSource.IsStatic && !MethodSource.IsNotCapturingLambda())
     {
         throw new NotSupportedException(
                   ErrorMessages.InvalidEntryPointInstanceKernelMethod);
     }
     if (IndexType == IndexType.None)
     {
         throw new NotSupportedException(
                   RuntimeErrorMessages.NotSupportedKernel);
     }
 }
Beispiel #10
0
        /// <summary>
        /// Perform all dot42 related Ast conversions.
        /// </summary>
        public static void Convert(DecompilerContext context, AstBlock ast, MethodSource currentMethod, AssemblyCompiler compiler)
        {
            if (ast.IsOptimizedForTarget)
                return;            
#if DEBUG
            //Debugger.Launch();
            if ((currentMethod.Method != null) && (currentMethod.Method.Name.Equals("runTest", StringComparison.OrdinalIgnoreCase)))
            {
                //Debugger.Launch();
            }
#endif

            IntPtrConverter.Convert(ast, compiler);
            TypeOfConverter.Convert(ast, compiler);
            BranchOptimizer.Convert(ast);
            CompoundAssignmentConverter.Convert(ast);
            ByReferenceParamConverter.Convert(context, ast, compiler);
            CompareUnorderedConverter.Convert(ast);
            EnumConverter.Convert(ast, compiler);
            EnumOptimizer.Convert(ast, compiler);

            // Keep this order
            NullableConverter.Convert(ast, compiler);
            PrimitiveAddressOfConverter.Convert(ast, currentMethod, compiler);
            StructCallConverter.Convert(ast, compiler);
            // end

            InitializeStructVariablesConverter.Convert(ast);
            DelegateConverter.Convert(ast);
            LdcWideConverter.Convert(ast);
            LdLocWithConversionConverter.Convert(ast);
            ConvertAfterLoadConversionConverter.Convert(ast);
            ConvertBeforeStoreConversionConverter.Convert(ast);
            CleanupConverter.Convert(ast);

            GenericsConverter.Convert(ast);

            // Expand cast expressions
            CastConverter.Convert(ast, currentMethod, compiler);

            // Expand generic instance information
            GenericInstanceConverter.Convert(ast, currentMethod, compiler);

        }
Beispiel #11
0
        /// <summary>
        /// Generate method code
        /// </summary>
        public void GenerateCode(ClassDefinition declaringClass, DexTargetPackage targetPackage)
        {
            if (dmethod == null)
            {
                return;
            }

            // Create body (if any)
            if (!method.HasCode)
            {
                return;
            }

            if (compiler.DxClassfileMethodBodyCompiler != null)
            {
                var dxBody = compiler.DxClassfileMethodBodyCompiler.GetMethodBody(dmethod, xMethod);
                if (dxBody == null)
                {
                    throw new Exception("unable to get method body through 'dx': " + dmethod);
                }

                dmethod.Body = dxBody;
                dmethod.Owner.SetSourceFile(dxBody.Owner.Owner.SourceFile);
                return;
            }

            var cachedBody = compiler.MethodBodyCompilerCache.GetFromCache(dmethod, xMethod, compiler, targetPackage);

            if (cachedBody != null)
            {
                dmethod.Body = cachedBody.Body;
                // important to fix the owners source file as early as possible,
                // so it can't be changed later. Else we would have to recreate
                // all cached method bodies debug infos.
                dmethod.Owner.SetSourceFile(cachedBody.ClassSourceFile);
                return;
            }

            //ExpandSequencePoints(method.Body);
            var source = new MethodSource(xMethod, method);

            DexMethodBodyCompiler.TranslateToRL(compiler, targetPackage, source, dmethod, false, out compiledMethod);
        }
        public static void Convert(AstNode ast, MethodSource currentMethod, AssemblyCompiler compiler)
        {
            // only work on MoveNext of IAsyncStateMachine implementations.
            if (currentMethod.Name != "MoveNext" && currentMethod.Name != "IAsyncStateMachine_MoveNext")
            {
                return;
            }
            var declaringType = currentMethod.Method.DeclaringType.Resolve();

            if (declaringType.Interfaces.All(i => i.FullName != "System.Runtime.CompilerServices.IAsyncStateMachine"))
            {
                return;
            }

            foreach (var block in ast.GetSelfAndChildrenRecursive <AstBlock>())
            {
                FixBlock(block);
            }
        }
        /// <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);
            }
        }
Beispiel #14
0
        /// <summary>
        /// Optimize expressions
        /// </summary>
        public static void Convert(AstNode ast, MethodSource currentMethod, AssemblyCompiler compiler)
        {
            var typeSystem = compiler.Module.TypeSystem;

            foreach (var node in ast.GetSelfAndChildrenRecursive <AstExpression>())
            {
                switch (node.Code)
                {
                case AstCode.InstanceOf:
                    ConvertInstanceOf(compiler, node, typeSystem);
                    break;

                case AstCode.Isinst:
                    ConvertIsInst(compiler, node, typeSystem);
                    break;

                case AstCode.Castclass:
                    ConvertCastclass(compiler, node, typeSystem);
                    break;

                case AstCode.Call:
                    ConvertAsNativeIFormattable(node, typeSystem);
                    break;

                case AstCode.Callvirt:
                    ConvertCallvirtIEnumerable(compiler, node, typeSystem);
                    break;

                // TODO: this might better be handled in RLBuilder.ConvertTypeBeforeStore()
                case AstCode.Ret:
                    ConvertRetOrStfldOrStsfld(compiler, currentMethod.Method.ReturnType, node, typeSystem);
                    break;

                // TODO: this appears to be handled in RLBuilder.ConvertTypeBeforeStore(),
                //       but is not. why?
                case AstCode.Stfld:
                case AstCode.Stsfld:
                    ConvertRetOrStfldOrStsfld(compiler, ((XFieldReference)node.Operand).FieldType, node, typeSystem);
                    break;
                }
            }
        }
Beispiel #15
0
 /// <summary>
 /// Generate an Return opcode.
 /// </summary>
 internal static RCode Return(this AstExpression expr, MethodSource currentMethod)
 {
     if (currentMethod.ReturnsDexWide)
     {
         return(RCode.Return_wide);
     }
     if (currentMethod.ReturnsVoid)
     {
         return(RCode.Return_void);
     }
     if (currentMethod.ReturnsDexValue)
     {
         return(RCode.Return);
     }
     if (currentMethod.ReturnsDexObject)
     {
         return(RCode.Return_object);
     }
     throw new ArgumentException("Unknown type in return " + currentMethod.FullName);
 }
        /// <summary>
        /// Add initialization code to the given constructor for non-initialized struct fields.
        /// </summary>
        private static void AddFieldInitializationCode(MethodSource ctor, AstBlock ast)
        {
            List <XFieldDefinition> fieldsToInitialize;
            var declaringType = ctor.Method.DeclaringType;
            var fieldsThatMayNeedInitialization = declaringType.Fields.Where(x => x.IsReachable && x.FieldType.IsEnum());
            var index = 0;

            if (ctor.Method.IsStatic)
            {
                fieldsToInitialize = fieldsThatMayNeedInitialization.Where(x => x.IsStatic && !IsInitialized(ast, x)).ToList();
                foreach (var field in fieldsToInitialize)
                {
                    var defaultExpr = new AstExpression(ast.SourceLocation, AstCode.DefaultValue, field.FieldType);
                    var initExpr    = new AstExpression(ast.SourceLocation, AstCode.Stsfld, field, defaultExpr);
                    ast.Body.Insert(index++, initExpr);
                }
            }
            else
            {
                // If there is a this ctor being called, we do not have to initialize here.
                var thisCalls = ast.GetSelfAndChildrenRecursive <AstExpression>(x => (x.Code == AstCode.Call) && ((XMethodReference)x.Operand).DeclaringType.IsSame(declaringType));
                if (thisCalls.Any(x => ((XMethodReference)x.Operand).Name == ".ctor"))
                {
                    return;
                }
                fieldsToInitialize = fieldsThatMayNeedInitialization.Where(x => !x.IsStatic && !IsInitialized(ast, x)).ToList();
                if (fieldsToInitialize.Any())
                {
                    var baseCall        = FindFirstBaseCtorCall(ast, declaringType);
                    var initExpressions = new List <AstExpression>();
                    foreach (var field in fieldsToInitialize)
                    {
                        var thisExpr    = new AstExpression(ast.SourceLocation, AstCode.Ldthis, null);
                        var defaultExpr = new AstExpression(ast.SourceLocation, AstCode.DefaultValue, field.FieldType);
                        initExpressions.Add(new AstExpression(ast.SourceLocation, AstCode.Stfld, field, thisExpr, defaultExpr));
                    }
                    InsertAfter(ast, baseCall, initExpressions);
                }
            }
        }
        protected SourceLocation FindFile(ScriptingContext context, string filename,
                                          int line)
        {
            SourceFile file = Session.FindFile(filename);

            if (file == null)
            {
                throw new ScriptingException("Cannot find source file `{0}'.",
                                             filename);
            }

            MethodSource source = file.FindMethod(line);

            if (source == null)
            {
                throw new ScriptingException(
                          "Cannot find method corresponding to line {0} in `{1}'.",
                          line, file.Name);
            }

            return(new SourceLocation(source, file, line));
        }
Beispiel #18
0
 /// <summary>
 /// Optimize expressions
 /// </summary>
 public static void Convert(AstNode ast, MethodSource currentMethod, AssemblyCompiler compiler)
 {
     foreach (var node in ast.GetExpressions(x => (x.Code == AstCode.Call) || (x.Code == AstCode.Calli) || (x.Code == AstCode.Callvirt)))
     {
         var method = (XMethodReference)node.Operand;
         XMethodDefinition methodDef;
         if (method.TryResolve(out methodDef) && methodDef.IsConstructor && methodDef.DeclaringType.IsPrimitive && (node.Arguments.Count == 2))
         {
             // primitive.ctor(addressof_primitive, value) -> primitive.cast(value)
             var locVar = node.Arguments[0].Operand;
             node.Arguments.RemoveAt(0);
             node.SetCode(AstCode.Stloc).SetType(node.Arguments[0].GetResultType()).Operand = locVar;
         }
         else
         {
             for (var i = 0; i < node.Arguments.Count; i++)
             {
                 ProcessArgument(node, method, i, currentMethod, compiler.Module);
             }
         }
     }
 }
 /// <summary>
 /// Optimize expressions
 /// </summary>
 public static void Convert(AstNode ast, MethodSource currentMethod, AssemblyCompiler compiler)
 {
     foreach (var node in ast.GetExpressions(x => (x.Code == AstCode.Call) || (x.Code == AstCode.Calli) || (x.Code == AstCode.Callvirt)))
     {
         var method = (XMethodReference)node.Operand;
         XMethodDefinition methodDef;
         if (method.TryResolve(out methodDef) && methodDef.IsConstructor && methodDef.DeclaringType.IsPrimitive && (node.Arguments.Count == 2))
         {
             // primitive.ctor(addressof_primitive, value) -> primitive.cast(value)
             var locVar = node.Arguments[0].Operand;
             node.Arguments.RemoveAt(0);
             node.SetCode(AstCode.Stloc).SetType(node.Arguments[0].GetResultType()).Operand = locVar;
         }
         else
         {
             for (var i = 0; i < node.Arguments.Count; i++)
             {
                 ProcessArgument(node, method, i, currentMethod, compiler.Module);
             }
         }
     }
 }
Beispiel #20
0
        /// <summary>
        /// Optimize expressions
        /// </summary>
        public static void Convert(AstNode ast, MethodSource currentMethod, AssemblyCompiler compiler)
        {
            var typeSystem = compiler.Module.TypeSystem;

            // Expand instanceof
            foreach (var node in ast.GetSelfAndChildrenRecursive <AstExpression>(x => x.Code == AstCode.InstanceOf))
            {
                ConvertInstanceOf(compiler, node, typeSystem);
            }

            // Expand isinst
            foreach (var node in ast.GetSelfAndChildrenRecursive <AstExpression>(x => x.Code == AstCode.Isinst))
            {
                ConvertIsInst(compiler, node, typeSystem);
            }

            // Expand Castclass
            foreach (var node in ast.GetSelfAndChildrenRecursive <AstExpression>(x => x.Code == AstCode.Castclass))
            {
                ConvertCastclass(compiler, node, typeSystem);
            }
        }
Beispiel #21
0
        /// <summary>
        /// Optimize expressions
        /// </summary>
        public static void Convert(AstNode ast, MethodSource currentMethod, AssemblyCompiler compiler)
        {
            var typeSystem = compiler.Module.TypeSystem;

            // Expand instanceof
            foreach (var node in ast.GetSelfAndChildrenRecursive<AstExpression>(x => x.Code == AstCode.InstanceOf))
            {
                ConvertInstanceOf(compiler, node, typeSystem);
            }

            // Expand isinst
            foreach (var node in ast.GetSelfAndChildrenRecursive<AstExpression>(x => x.Code == AstCode.Isinst))
            {
                ConvertIsInst(compiler, node, typeSystem);
            }

            // Expand Castclass
            foreach (var node in ast.GetSelfAndChildrenRecursive<AstExpression>(x => x.Code == AstCode.Castclass))
            {
                ConvertCastclass(compiler, node, typeSystem);
            }
        }
        private readonly Stack <FinallyBlockState> tryCatchStack   = new Stack <FinallyBlockState>(); // holds the current finally target.

        /// <summary>
        /// Default ctor
        /// </summary>
        internal AstCompilerVisitor(AssemblyCompiler compiler, MethodSource source, DexTargetPackage targetPackage, MethodDefinition method, MethodBody body)
        {
            this.compiler      = compiler;
            currentMethod      = source;
            this.targetPackage = targetPackage;
            currentDexMethod   = method;
            this.body          = body;
            frame        = new AstInvocationFrame(targetPackage, method, source, body);
            instructions = body.Instructions;

            // Base class class ctor for structs
            if (source.IsDotNet && (source.Name == ".ctor") && (source.ILMethod.DeclaringType.IsValueType))
            {
                var ilMethod = source.ILMethod;
                if (!HasBaseOrThisClassCtorCall(ilMethod))
                {
                    // Add a call to the base class ctor now
                    var seqp     = SequencePointWrapper.Wrap(ilMethod.Body.Instructions.Select(x => x.SequencePoint(ilMethod.Body)).FirstOrDefault());
                    var baseCtor = new MethodReference(method.Owner.SuperClass, "<init>", new Prototype(PrimitiveType.Void));
                    this.Add(seqp, RCode.Invoke_direct, baseCtor, frame.ThisArgument);
                }
            }

            // Store any genericInstance argument

            /*if (source.Method.NeedsGenericInstanceTypeParameter && (source.Name == ".ctor"))
             * {
             *  var owner = method.Owner;
             *  var ilMethod = source.ILMethod;
             *  var giField = owner.GenericInstanceField;
             *  if (giField == null)
             *  {
             *      throw new CompilerException(string.Format("Expected GenericInstance field in {0}", ilMethod.FullName));
             *  }
             *  var seqp = SequencePointWrapper.Wrap(ilMethod.Body.Instructions.Select(x => x.SequencePoint).FirstOrDefault());
             *  this.Add(seqp, RCode.Iput_object, giField, frame.GenericInstanceTypeArgument, frame.ThisArgument);
             * }*/
        }
Beispiel #23
0
 /// <summary>
 /// Add initialization code to the given constructor for non-initialized struct fields.
 /// </summary>
 private static void AddFieldInitializationCode(MethodSource ctor, AstBlock ast)
 {
     List<XFieldDefinition> fieldsToInitialize;
     var declaringType = ctor.Method.DeclaringType;
     var fieldsThatMayNeedInitialization = declaringType.Fields.Where(x => x.IsReachable && x.FieldType.IsEnum());
     var index = 0;
     if (ctor.Method.IsStatic)
     {
         fieldsToInitialize = fieldsThatMayNeedInitialization.Where(x => x.IsStatic && !IsInitialized(ast, x)).ToList();
         foreach (var field in fieldsToInitialize)
         {
             var defaultExpr = new AstExpression(ast.SourceLocation, AstCode.DefaultValue, field.FieldType);
             var initExpr = new AstExpression(ast.SourceLocation, AstCode.Stsfld, field, defaultExpr);
             ast.Body.Insert(index++, initExpr);
         }
     }
     else
     {
         // If there is a this ctor being called, we do not have to initialize here.
         var thisCalls = ast.GetSelfAndChildrenRecursive<AstExpression>(x => (x.Code == AstCode.Call) && ((XMethodReference) x.Operand).DeclaringType.IsSame(declaringType));
         if (thisCalls.Any(x => ((XMethodReference) x.Operand).Name == ".ctor"))
             return;
         fieldsToInitialize = fieldsThatMayNeedInitialization.Where(x => !x.IsStatic && !IsInitialized(ast, x)).ToList();
         if (fieldsToInitialize.Any())
         {
             var baseCall = FindFirstBaseCtorCall(ast, declaringType);
             var initExpressions = new List<AstExpression>();
             foreach (var field in fieldsToInitialize)
             {
                 var thisExpr = new AstExpression(ast.SourceLocation, AstCode.Ldthis, null);
                 var defaultExpr = new AstExpression(ast.SourceLocation, AstCode.DefaultValue, field.FieldType);
                 initExpressions.Add(new AstExpression(ast.SourceLocation, AstCode.Stfld, field, thisExpr, defaultExpr));
             }
             InsertAfter(ast, baseCall, initExpressions);
         }
     }
 }
Beispiel #24
0
        void print_address_func(long address)
        {
            TargetAddress maddress = new TargetAddress(
                memory.AddressDomain, address);

            if (current_method != null)
            {
                try {
                    MethodSource method = current_method.GetTrampoline(
                        memory, maddress);

                    if (method != null)
                    {
                        output_func(method.Name);
                        return;
                    }
                } catch (TargetException) {
                }
            }

            Symbol name = null;

            if (process != null)
            {
                name = process.SymbolTableManager.SimpleLookup(maddress, false);
            }

            if (name == null)
            {
                output_func(address);
            }
            else
            {
                output_func(String.Format("0x{0:x}:{1}", address, name.ToString()));
            }
        }
Beispiel #25
0
        /// <summary>
        /// Optimize expressions
        /// </summary>
        public static void Convert(AstNode ast, MethodSource currentMethod, AssemblyCompiler compiler)
        {
            var typeSystem = compiler.Module.TypeSystem;

            foreach (var node in ast.GetSelfAndChildrenRecursive<AstExpression>())
            {
                switch (node.Code)
                {
                    case AstCode.InstanceOf:
                        ConvertInstanceOf(compiler, node, typeSystem);
                        break;
                    case AstCode.Isinst:
                        ConvertIsInst(compiler, node, typeSystem);
                        break;
                    case AstCode.Castclass:
                        ConvertCastclass(compiler, node, typeSystem);
                        break;
                    case AstCode.Call:
                        ConvertAsNativeIFormattable(node, typeSystem);
                        break;
                    case AstCode.Callvirt:
                        ConvertCallvirtIEnumerable(compiler, node, typeSystem);
                        break;
                    // TODO: this might better be handled in RLBuilder.ConvertTypeBeforeStore()
                    case AstCode.Ret:
                        ConvertRetOrStfldOrStsfld(compiler, currentMethod.Method.ReturnType, node, typeSystem);
                        break;
                    // TODO: this appears to be handled in RLBuilder.ConvertTypeBeforeStore(),
                    //       but is not. why?
                    case AstCode.Stfld:
                    case AstCode.Stsfld:
                        ConvertRetOrStfldOrStsfld(compiler, ((XFieldReference)node.Operand).FieldType, node, typeSystem);
                        break;
                }
            }
        }
Beispiel #26
0
 /// <summary>
 /// Generate an Return opcode.
 /// </summary>
 internal static RCode Return(this AstExpression expr, MethodSource currentMethod)
 {
     if (currentMethod.ReturnsDexWide) return RCode.Return_wide;
     if (currentMethod.ReturnsVoid) return RCode.Return_void;
     if (currentMethod.ReturnsDexValue) return RCode.Return;
     if (currentMethod.ReturnsDexObject) return RCode.Return_object;
     throw new ArgumentException("Unknown type in return " + currentMethod.FullName);
 }
        /// <summary>
        /// Create an expression that loads the given type at runtime.
        /// </summary>
        private static AstExpression LoadTypeForGenericInstance(ISourceLocation seqp, MethodSource currentMethod,
                                                                XTypeReference type, AssemblyCompiler compiler, XTypeDefinition typeHelperType, XTypeSystem typeSystem,
                                                                TypeConversion typeConversion, XGenericInstanceType typeGenericArguments = null)
        {
            if (type.IsArray)
            {
                // Array type
                var arrayType = (XArrayType)type;
                // Load element type
                var prefix = LoadTypeForGenericInstance(seqp, currentMethod, ((XArrayType)type).ElementType, compiler, typeHelperType, typeSystem, typeConversion);
                // Convert to array type
                if (arrayType.Dimensions.Count() == 1)
                {
                    var giCreateArray = typeHelperType.Methods.Single(x => (x.Name == "Array") && (x.Parameters.Count == 1));
                    return(new AstExpression(seqp, AstCode.Call, giCreateArray, prefix)
                    {
                        ExpectedType = typeSystem.Type
                    });
                }
                else
                {
                    var giCreateArray  = typeHelperType.Methods.Single(x => (x.Name == "Array") && (x.Parameters.Count == 2));
                    var dimensionsExpr = new AstExpression(seqp, AstCode.Ldc_I4, arrayType.Dimensions.Count())
                    {
                        ExpectedType = typeSystem.Int
                    };
                    return(new AstExpression(seqp, AstCode.Call, giCreateArray, prefix, dimensionsExpr)
                    {
                        ExpectedType = typeSystem.Type
                    });
                }
            }

            var gp = type as XGenericParameter;

            if (gp != null)
            {
                AstExpression loadExpr;
                if (gp.Owner is XTypeReference)
                {
                    // Class type parameter
                    var owner = (XTypeReference)gp.Owner;
                    if (owner.GetElementType().Resolve().HasDexImportAttribute())
                    {
                        // Imported type
                        return(new AstExpression(seqp, AstCode.TypeOf, typeSystem.Object)
                        {
                            ExpectedType = typeSystem.Type
                        });
                    }
                    if (currentMethod.IsClassCtor)
                    {
                        // Class ctor's cannot have type information.
                        // Return Object instead
                        if (currentMethod.IsDotNet && !currentMethod.ILMethod.DeclaringType.HasSuppressMessageAttribute("StaticConstructorUsesGenericParameter"))
                        {
                            var msg = "Class (static) constructor of '{0}' tries to use generic parameter. This will always yield Object. " +
                                      "You can suppress this warning with a [SuppressMessage(\"dot42\", \"StaticConstructorUsesGenericParameter\")] " +
                                      "attribute on the class.";

                            if (seqp != null && seqp.Document != null)
                            {
                                DLog.Warning(DContext.CompilerCodeGenerator, seqp.Document, seqp.StartColumn, seqp.StartLine, msg, currentMethod.DeclaringTypeFullName);
                            }
                            else
                            {
                                DLog.Warning(DContext.CompilerCodeGenerator, msg, currentMethod.DeclaringTypeFullName);
                            }
                        }
                        return(new AstExpression(seqp, AstCode.TypeOf, typeSystem.Object)
                        {
                            ExpectedType = typeSystem.Type
                        });
                    }
                    loadExpr = currentMethod.IsStatic ?
                               LoadStaticClassGenericArgument(seqp, typeSystem, currentMethod.Method, gp.Position) :
                               LoadInstanceClassGenericArgument(seqp, typeSystem, currentMethod.Method.DeclaringType, gp.Position);
                }
                else
                {
                    // Method type parameter
                    var owner = (XMethodReference)gp.Owner;
                    if (owner.GetElementMethod().Resolve().DeclaringType.HasDexImportAttribute())
                    {
                        // Imported type
                        return(LoadTypeForGenericInstance(seqp, currentMethod, type.Module.TypeSystem.Object, compiler, typeHelperType, typeSystem, typeConversion));
                    }
                    loadExpr = LoadMethodGenericArgument(seqp, typeSystem, currentMethod.Method, gp.Position);
                }

                if (typeConversion == TypeConversion.EnsureRuntimeType)
                {
                    return(EnsureGenericRuntimeType(loadExpr, typeSystem, typeHelperType));
                }
                else
                {
                    return(loadExpr);
                }
            }

            if (type is XTypeSpecification)
            {
                var typeSpec = (XTypeSpecification)type;
                var git      = type as XGenericInstanceType;
                var baseType = LoadTypeForGenericInstance(seqp, currentMethod, typeSpec.ElementType, compiler, typeHelperType, typeSystem, typeConversion, git);

                if (typeConversion != TypeConversion.EnsureTrueOrMarkerType || typeSpec.GetElementType().IsNullableT())
                {
                    return(baseType);
                }

                // Use the element type and make a generic proxy with the generic arguments.
                var parameters = CreateGenericInstanceCallArguments(seqp, git, currentMethod, compiler);
                if (parameters.Count == 1 && parameters[0].GetResultType().IsArray)
                {
                    // array type call.
                    var method = typeHelperType.Methods.Single(m => m.Name == "GetGenericInstanceType" && m.Parameters.Count == 2 && m.Parameters[1].ParameterType.IsArray);
                    return(new AstExpression(seqp, AstCode.Call, method, baseType, parameters[0]));
                }
                else
                {
                    parameters.Insert(0, baseType);
                    var method = typeHelperType.Methods.Single(m => m.Name == "GetGenericInstanceType" && m.Parameters.Count == parameters.Count && !m.Parameters[1].ParameterType.IsArray);
                    return(new AstExpression(seqp, AstCode.Call, method, parameters.ToArray()));
                }
            }


            if (typeConversion == TypeConversion.EnsureTrueOrMarkerType && type.GetElementType().IsNullableT())
            {
                if (typeGenericArguments != null)
                {
                    var underlying = typeGenericArguments.GenericArguments[0];
                    var code       = underlying.IsPrimitive ? AstCode.BoxedTypeOf : AstCode.NullableTypeOf;
                    return(new AstExpression(seqp, code, underlying)
                    {
                        ExpectedType = typeSystem.Type
                    });
                }
                // if typeGenericArguments is null, this is a generic definition, e.g. typeof(Nullable<>).
            }

            // Plain type reference or definition
            return(new AstExpression(seqp, AstCode.TypeOf, type)
            {
                ExpectedType = typeSystem.Type
            });
        }
 public static bool ValidForRestriction(this MethodSource source, SourceRestrictions restriction)
 {
     return((MethodSource)((int)restriction & (int)source) == source);
 }
Beispiel #29
0
        /// <summary>
        /// Optimize expressions
        /// </summary>
        public static void Convert(AstNode ast, MethodSource currentMethod, XTypeSystem typeSystem)
        {
            // Expand typeof
            foreach (var pair in ast.GetExpressionPairs())
            {
                var node = pair.Expression;
                switch (node.Code)
                {
                    case AstCode.Ldfld:
                    //case AstCode.Ldsfld: // NOT YET
                        {
                            var field = (XFieldReference) node.Operand;
                            UnboxIfGeneric(field.FieldType, node, typeSystem);
                        }
                        break;
                    case AstCode.Stfld:
                        {
                            var field = (XFieldReference)node.Operand;
                            BoxIfGeneric(field.FieldType, node.Arguments[1]);
                        }
                        break;
                    case AstCode.Call:
                    case AstCode.Calli:
                    case AstCode.Callvirt:
                        {
                            var method = (XMethodReference)node.Operand;
                            if ((!method.ReturnType.IsVoid()) && (pair.Parent != null))
                            {
                                UnboxIfGeneric(method.ReturnType, node, typeSystem);
                            }
                        }
                        break;
                    case AstCode.Ret:
                        {
                            if (node.Arguments.Count > 0)
                            {
                                var expectedType = currentMethod.Method.ReturnType;
                                BoxIfGeneric(expectedType, node.Arguments[0]);
                            }
                        }
                        break;
                    case AstCode.Box:
                        {
                            var type = (XTypeReference)node.Operand;

                            // Honestly, the whole Generics code seems to be quite
                            // complex. I hope this fix does not break anything else.
                            // Also: is there any sense in having two codes 'box' and 'boxtogeneric'?

                            // The Rosyln compiler apparently uses 'box' instructions to satisfy
                            // generic constraints. Not sure if this is the right place to handle 
                            // this. 
                            // What we want to achive is to perform this conversion code only if the
                            // expected type is assignable from any of the constraints. As we do not
                            // have an 'IsAssignableFrom' logic for XTypes, a simpler check must suffice.
                            
                            if (type.IsGenericParameter 
                                && ((XGenericParameter)type).Constraints.Any() 
                                && node.ExpectedType != null && !node.ExpectedType.IsPrimitive
                                && !node.ExpectedType.IsGenericParameter)
                            {
                                // or just enter the required cast here???
                                node.Code = AstCode.BoxToGeneric;
                                node.InferredType = node.ExpectedType;
                            }
                        }
                        break;
                    case AstCode.ByRefArray:
                    case AstCode.ByRefOutArray:
                    {
                        if (node.Arguments.Count > 1)
                        {
                            var originalType = (XTypeReference) node.Arguments[1].Operand;
                            UnboxByRefIfGeneric(originalType, node.StoreByRefExpression, typeSystem);
                        }
                    }
                    break;
                }
            }
        }
Beispiel #30
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)
            {
                GenericInstanceTypeArguments = new List <ArgumentRegisterSpec>();
                foreach (var param in prototype.GenericInstanceTypeParameters)
                {
                    var r = (ArgumentRegisterSpec)Allocate(param.Type, false, RCategory.Argument, null);
                    GenericInstanceTypeArguments.Add(r);
                    arguments.Add(r);
                }
            }
            // Add GenericInstanceMethod parameter (if any)
            if (source.Method.NeedsGenericInstanceMethodParameter)
            {
                GenericInstanceMethodArguments = new List <ArgumentRegisterSpec>();
                foreach (var param in prototype.GenericInstanceMethodParameters)
                {
                    var r = (ArgumentRegisterSpec)Allocate(param.Type, false, RCategory.Argument, null);
                    GenericInstanceMethodArguments.Add(r);
                    arguments.Add(r);
                }
            }
            // 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));
            }
        }
        /// <summary>
        /// Optimize expressions
        /// </summary>
        public static void Convert(AstNode ast, MethodSource currentMethod, AssemblyCompiler compiler)
        {
            foreach (var node in ast.GetExpressions(x => (x.Code == AstCode.Call) || (x.Code == AstCode.Calli) || (x.Code == AstCode.Callvirt)))
            {
                var  method    = (XMethodReference)node.Operand;
                bool processed = false;
                XMethodDefinition methodDef;

                if (method.TryResolve(out methodDef) && methodDef.DeclaringType.IsPrimitive)
                {
                    if (methodDef.IsConstructor && (node.Arguments.Count == 2))
                    {
                        // primitive.ctor(addressof_primitive, value) -> primitive.cast(value)
                        var locVar = node.Arguments[0].Operand;
                        node.Arguments.RemoveAt(0);
                        node.SetCode(AstCode.Stloc).SetType(node.Arguments[0].GetResultType()).Operand = locVar;
                        processed = true;
                    }
                    else if (methodDef.Name == "GetHashCode" && node.Arguments.Count == 1 && methodDef.HasThis)
                    {
                        // we try to avoid boxing.
                        var arg = node.Arguments[0];


                        switch (arg.Code)
                        {
                        case AstCode.AddressOf:
                            arg = arg.Arguments[0];
                            break;

                        case AstCode.Ldloca:
                            arg.SetCode(AstCode.Ldloc);
                            arg.SetType(arg.InferredType.ElementType);
                            break;

                        case AstCode.Ldflda:
                            arg.SetCode(AstCode.Ldfld);
                            arg.SetType(arg.InferredType.ElementType);
                            break;

                        case AstCode.Ldsflda:
                            arg.SetCode(AstCode.Ldsfld);
                            arg.SetType(arg.InferredType.ElementType);
                            break;

                        case AstCode.Ldelema:
                            arg.SetCode(AstCode.Ldelem_Any);
                            arg.SetType(arg.InferredType.ElementType);
                            break;
                        }

                        var type = arg.GetResultType();

                        if (type.IsBoolean() ||
                            type.IsFloat() || type.IsDouble() ||
                            type.IsInt64() || type.IsUInt64())
                        {
                            var ch = compiler.GetDot42InternalType("CompilerHelper").Resolve();

                            // these need special handling

                            var replMethod = ch.Methods.FirstOrDefault(m => m.Name == "GetHashCode" && m.IsStatic &&
                                                                       m.Parameters[0].ParameterType.IsSame(type, true));
                            if (replMethod != null)
                            {
                                node.Operand = replMethod;
                                node.SetCode(AstCode.Call);
                                node.Arguments.Clear();
                                node.Arguments.Add(arg);
                            }
                        }
                        else
                        {
                            // for the other primitive types, we just return the value itself.
                            node.CopyFrom(arg);
                            node.ExpectedType = compiler.Module.TypeSystem.Int;
                        }

                        processed = true;
                    }
                }

                if (!processed)
                {
                    for (var i = 0; i < node.Arguments.Count; i++)
                    {
                        ProcessArgument(node, method, i, currentMethod, compiler.Module);
                    }
                }
            }
        }
Beispiel #32
0
        public static void Convert(AstNode ast, MethodSource currentMethod, AssemblyCompiler compiler)
        {
            foreach (var block in ast.GetSelfAndChildrenRecursive <AstBlock>())
            {
                for (int i = 0; i < block.Body.Count; ++i)
                {
                    var expr = block.Body[i] as AstExpression;
                    if (expr == null)
                    {
                        continue;
                    }


                    var interlockedPairs = expr.GetExpressionPairs(p =>
                                                                   p.Code == AstCode.Call &&
                                                                   ((XMethodReference)p.Operand).DeclaringType.FullName == "System.Threading.Interlocked")
                                           .ToList();

                    if (interlockedPairs.Count == 0)
                    {
                        continue;
                    }
                    if (interlockedPairs.Count > 1)
                    {
                        throw new CompilerException("The Interlocked converter can not handle more than one interlocked call per statement. Try splittig the statement up.");
                    }

                    var interlockedCall = interlockedPairs.First().Expression;

                    // first parameter should be a reference to a field,
                    // (but be lenient if we don't find what we expect)

                    var targetExpr = interlockedCall.Arguments[0];

                    XFieldReference field = null;

                    if (targetExpr.InferredType.IsByReference)
                    {
                        field = targetExpr.Operand as XFieldReference;

                        if (field != null)
                        {
                            // check if we have an atomic updater
                            var updater = field.DeclaringType.Resolve().Fields
                                          .FirstOrDefault(f => f.Name == field.Name + NameConstants.Atomic.FieldUpdaterPostfix);
                            if (updater != null)
                            {
                                var method     = (XMethodReference)interlockedCall.Operand;
                                var methodName = method.Name.Split('$')[0]; // retrieve original name.

                                if (InterlockedUsingUpdater(interlockedCall, methodName, field, updater, targetExpr, interlockedPairs.First().Parent, compiler))
                                {
                                    continue;
                                }
                            }
                        }
                    }


                    FailsafeInterlockedUsingLocking(field, expr, targetExpr, block, i, compiler, currentMethod);
                }
            }
        }
Beispiel #33
0
        public static void Convert(AstBlock ast, MethodSource currentMethod, AssemblyCompiler compiler)
        {
            var setInstructionTarget = new AstGeneratedVariable(DebuggerConstants.SetNextInstructionVariableName, null, true)
            {
                Type = compiler.Module.TypeSystem.Bool
            };

            int labelCount = 0;
            var initExpr   = new AstExpression(AstNode.NoSource, AstCode.Stloc, setInstructionTarget,
                                               new AstExpression(AstNode.NoSource, AstCode.Ldnull, null)
                                               .SetType(compiler.Module.TypeSystem.Int));

            int lastBaseCtorCall = -1;

            // can't jump before base-class constructor call.
            if (currentMethod.IsCtor)
            {
                lastBaseCtorCall = FindLastCtorCall(ast);
            }

            ISourceLocation currentLoc = null;

            foreach (var block in ast.GetSelfAndChildrenRecursive <AstBlock>())
            {
                if (block.EntryGoto != null) // only handle simple cases atm.
                {
                    return;
                }

                var      body  = block.Body;
                AstLabel label = null;
                int      firstValidExpression = -1;
                bool     lastExprWasCall      = false;

                var startIdx = lastBaseCtorCall == -1?0:lastBaseCtorCall + 1;
                lastBaseCtorCall = -1;

                for (int idx = startIdx; idx < body.Count; ++idx)
                {
                    var expr = body[idx] as AstExpression;
                    if (expr == null)
                    {
                        continue;
                    }

                    if (expr.SourceLocation == null)
                    {
                        continue;
                    }

                    if (expr.SourceLocation.Equals(currentLoc) && !lastExprWasCall)
                    {
                        continue;
                    }

                    currentLoc = expr.SourceLocation;

                    lastExprWasCall = expr.Code.IsCall();

                    if (firstValidExpression == -1)
                    {
                        firstValidExpression = idx;
                        continue;
                    }

                    AddJumpInstruction(body, currentLoc, setInstructionTarget, ref idx,
                                       ref label, firstValidExpression, initExpr, ref labelCount);
                }

                //if (!lastExprWasRet && firstValidExpression != -1)
                //{
                //    int idx = body.Count;
                //    AddJumpInstruction(body, currentLoc, setInstructionTarget, ref idx,
                //                       ref label, firstValidExpression, initExpr, ref labelCount);
                //}
            }
        }
Beispiel #34
0
 /// <summary>
 /// Get a compiled method info for the given method.
 /// Create if needed.
 /// </summary>
 private CompiledMethod GetOrCreateCompileMethod(MethodSource method)
 {
     return(GetOrCreateCompileMethod(method.Method));
 }
Beispiel #35
0
        private static void FailsafeInterlockedUsingLocking(XFieldReference field, AstExpression expr,
                                                            AstExpression targetExpr, AstBlock block, int idx,
                                                            AssemblyCompiler compiler, MethodSource currentMethod)
        {
            if (currentMethod.IsDotNet && !currentMethod.ILMethod.DeclaringType.HasSuppressMessageAttribute("InterlockedFallback"))
            {
                bool isStatic = field != null && field.Resolve().IsStatic;

                DLog.Warning(DContext.CompilerCodeGenerator,
                             "Emulating Interlocked call using failsafe locking mechanism in {0}{1}. Consider using AtomicXXX classes instead. You can suppress this message with an [SuppressMessage(\"dot42\", \"InterlockedFallback\")] attribute on the class.",
                             currentMethod.Method.FullName, !isStatic ? "" : " because a static field is referenced");
            }

            // replace with:
            //    Monitor.Enter();
            //    try { <original expression> } finally { Monitor.Exit(); }
            //
            // note that the lock is larger than it has to be, since it also sourrounds
            // the parameter evaluation.
            // It must sourround the storing and loading of the reference parameters though.
            var typeSystem = compiler.Module.TypeSystem;

            var monitorType = compiler.GetDot42InternalType("System.Threading", "Monitor");
            var enterMethod = monitorType.Resolve().Methods.Single(p => p.Name == "Enter");
            var exitMethod  = monitorType.Resolve().Methods.Single(p => p.Name == "Exit");

            AstExpression loadLockTarget = null;

            if (field != null)
            {
                if (field.Resolve().IsStatic)
                {
                    // lock on the field's class typedef.
                    // but always the element type, not on a generic instance (until Dot42 implements proper generic static field handling)
                    loadLockTarget = new AstExpression(expr.SourceLocation, AstCode.LdClass, field.DeclaringType.GetElementType())
                                     .SetType(typeSystem.Type);
                }
                else
                {
                    // lock on the fields object
                    loadLockTarget = targetExpr.Arguments[0];
                }
            }

            if (loadLockTarget == null)
            {
                // something went wrong. use a global lock.
                DLog.Warning(DContext.CompilerCodeGenerator, "unable to infer target of Interlocked call. using global lock.");
                var interlockedType = compiler.GetDot42InternalType("System.Threading", "Interlocked");
                loadLockTarget = new AstExpression(expr.SourceLocation, AstCode.LdClass, interlockedType)
                                 .SetType(typeSystem.Type);
            }

            var lockVar = new AstGeneratedVariable("lockTarget$", "")
            {
                Type = typeSystem.Object
            };
            var storeLockVar = new AstExpression(expr.SourceLocation, AstCode.Stloc, lockVar, loadLockTarget);
            var loadLockVar  = new AstExpression(expr.SourceLocation, AstCode.Ldloc, lockVar);
            var enterCall    = new AstExpression(expr.SourceLocation, AstCode.Call, enterMethod, storeLockVar);

            var replacementBlock = new AstBlock(expr.SourceLocation);

            replacementBlock.Body.Add(enterCall);

            var tryCatch = new AstTryCatchBlock(expr.SourceLocation)
            {
                TryBlock     = new AstBlock(expr.SourceLocation, expr),
                FinallyBlock = new AstBlock(expr.SourceLocation,
                                            new AstExpression(block.SourceLocation, AstCode.Call, exitMethod, loadLockVar))
            };

            replacementBlock.Body.Add(tryCatch);

            if (block.EntryGoto == expr)
            {
                block.EntryGoto = enterCall;
            }

            block.Body[idx] = replacementBlock;
        }
Beispiel #36
0
        /// <summary>
        /// Perform all dot42 related Ast conversions.
        /// </summary>
        public static void Convert(DecompilerContext context, AstBlock ast, MethodSource currentMethod, AssemblyCompiler compiler, StopAstConversion stop = StopAstConversion.None)
        {
            if (ast.IsOptimizedForTarget)
                return;            
#if DEBUG
            //Debugger.Launch();
            if ((currentMethod.Method != null) && (currentMethod.Method.Name.Equals("runTest", StringComparison.OrdinalIgnoreCase)))
            {
                //Debugger.Launch();
            }
#endif
            
            IntPtrConverter.Convert(ast, compiler);
            if (stop == StopAstConversion.AfterIntPtrConverter) return;
            
            TypeOfConverter.Convert(ast, compiler);
            if (stop == StopAstConversion.AfterTypeOfConverter) return;
            
            // TODO: check if we actually need this optimizer, as we have a more throughoutful
            //       optimizer as the last step.
            BranchOptimizer.Convert(ast);
            if (stop == StopAstConversion.AfterBranchOptimizer) return;

            CompoundAssignmentConverter.Convert(ast);
            if (stop == StopAstConversion.AfterCompoundAssignmentConverter) return;

            // keep this order
            FixAsyncStateMachine.Convert(ast, currentMethod, compiler);
            if (stop == StopAstConversion.AfterFixAsyncStateMachine) return;

            InterlockedConverter.Convert(ast, currentMethod, compiler);
            if (stop == StopAstConversion.AfterInterlockedConverter) return;
            
            ByReferenceParamConverter.Convert(context, ast, compiler);
            if (stop == StopAstConversion.AfterByReferenceParamConverter) return;

            // end
            CompareUnorderedConverter.Convert(ast);
            if (stop == StopAstConversion.AfterCompareUnorderedConverter) return;
            
            EnumConverter.Convert(ast, compiler);
            if (stop == StopAstConversion.AfterEnumConverter) return;
            
            EnumOptimizer.Convert(ast, compiler);
            if (stop == StopAstConversion.AfterEnumOptimizer) return;

            // Keep this order
            NullableConverter.Convert(ast, compiler);
            if (stop == StopAstConversion.AfterNullableConverter) return;
            
            PrimitiveAddressOfConverter.Convert(ast, currentMethod, compiler);
            if (stop == StopAstConversion.AfterPrimitiveAddressOfConverter) return;
            
            StructCallConverter.Convert(ast, compiler);
            if (stop == StopAstConversion.AfterStructCallConverter) return;
            // end

            
            InitializeStructVariablesConverter.Convert(ast);
            if (stop == StopAstConversion.AfterInitializeStructVariablesConverter) return;
            
            DelegateConverter.Convert(ast);
            if (stop == StopAstConversion.AfterDelegateConverter) return;
            
            LdcWideConverter.Convert(ast);
            if (stop == StopAstConversion.AfterLdcWideConverter) return;
            
            LdLocWithConversionConverter.Convert(ast);
            if (stop == StopAstConversion.AfterLdLocWithConversionConverter) return;
            
            ConvertAfterLoadConversionConverter.Convert(ast);
            if (stop == StopAstConversion.AfterConvertAfterLoadConversionConverter) return;
            
            ConvertBeforeStoreConversionConverter.Convert(ast);
            if (stop == StopAstConversion.AfterConvertBeforeStoreConversionConverter) return;

            CleanupConverter.Convert(ast);
            if (stop == StopAstConversion.AfterCleanupConverter) return;

            GenericsConverter.Convert(ast, currentMethod, compiler.Module.TypeSystem);
            if (stop == StopAstConversion.AfterGenericsConverter) return;

            // Expand cast expressions
            CastConverter.Convert(ast, currentMethod, compiler);
            if (stop == StopAstConversion.AfterCastConverter) return;
            
            // Expand generic instance information
            GenericInstanceConverter.Convert(ast, currentMethod, compiler);
            if (stop == StopAstConversion.AfterGenericInstanceConverter) return;
            
            // run the branch optimizer again. (do we need the first invocation?)
            BranchOptimizer2.Convert(ast, compiler);
            if (stop == StopAstConversion.AfterBranchOptimizer2) return;

        }
Beispiel #37
0
        public DynamicSourceLocation(MethodSource source, SourceFile file, int line, int column)
        {
            if (source.IsManaged) {
                this.function = source.Function;
                this.module = function.Module;
            } else {
                this.module = source.Module;
                this.source = source;
            }

            this.file = file;
            this.line = line;
            this.column = column;
        }
Beispiel #38
0
        /// <summary>
        /// Generate method code
        /// </summary>
        public virtual void GenerateCode(ClassDefinition declaringClass, DexTargetPackage targetPackage)
        {
            if (dmethod == null)
                return;

            // Create body (if any)
            if (method.HasBody)
            {
                ExpandSequencePoints(method.Body);
                var source = new MethodSource(xMethod, method);
                DexMethodBodyCompiler.TranslateToRL(compiler, targetPackage, source, dmethod, out compiledMethod);
            }
        }
Beispiel #39
0
 public void PrintMethods(MethodSource[] methods)
 {
     for (int i = 0; i < methods.Length; i++) {
         interpreter.Print ("{0,4}  {1}", i+1, methods [i].Name);
     }
 }
 public static bool AllowsSource(this SourceRestrictions restriction, MethodSource source)
 {
     return(source.ValidForRestriction(restriction));
 }
        /// <summary>
        /// Optimize expressions
        /// </summary>
        public static void Convert(AstNode ast, MethodSource currentMethod, XTypeSystem typeSystem)
        {
            // Expand typeof
            foreach (var pair in ast.GetExpressionPairs())
            {
                var node = pair.Expression;
                switch (node.Code)
                {
                case AstCode.Ldfld:
                    //case AstCode.Ldsfld: // NOT YET
                {
                    var field = (XFieldReference)node.Operand;
                    UnboxIfGeneric(field.FieldType, node, typeSystem);
                }
                break;

                case AstCode.Stfld:
                {
                    var field = (XFieldReference)node.Operand;
                    BoxIfGeneric(field.FieldType, node.Arguments[1]);
                }
                break;

                case AstCode.Call:
                case AstCode.Calli:
                case AstCode.Callvirt:
                {
                    var method = (XMethodReference)node.Operand;
                    if ((!method.ReturnType.IsVoid()) && (pair.Parent != null))
                    {
                        UnboxIfGeneric(method.ReturnType, node, typeSystem);
                    }
                }
                break;

                case AstCode.Ret:
                {
                    if (node.Arguments.Count > 0)
                    {
                        var expectedType = currentMethod.Method.ReturnType;
                        BoxIfGeneric(expectedType, node.Arguments[0]);
                    }
                }
                break;

                case AstCode.Box:
                {
                    var type = (XTypeReference)node.Operand;

                    // Honestly, the whole Generics code seems to be quite
                    // complex. I hope this fix does not break anything else.
                    // Also: is there any sense in having two codes 'box' and 'boxtogeneric'?

                    // The Rosyln compiler apparently uses 'box' instructions to satisfy
                    // generic constraints. Not sure if this is the right place to handle
                    // this.
                    // What we want to achive is to perform this conversion code only if the
                    // expected type is assignable from any of the constraints. As we do not
                    // have an 'IsAssignableFrom' logic for XTypes, a simpler check must suffice.

                    if (type.IsGenericParameter &&
                        ((XGenericParameter)type).Constraints.Any() &&
                        node.ExpectedType != null && !node.ExpectedType.IsPrimitive &&
                        !node.ExpectedType.IsGenericParameter)
                    {
                        // or just enter the required cast here???
                        node.Code         = AstCode.BoxToGeneric;
                        node.InferredType = node.ExpectedType;
                    }
                }
                break;

                case AstCode.ByRefArray:
                case AstCode.ByRefOutArray:
                {
                    if (node.Arguments.Count > 1)
                    {
                        var originalType = (XTypeReference)node.Arguments[1].Operand;
                        UnboxByRefIfGeneric(originalType, node.StoreByRefExpression, typeSystem);
                    }
                }
                break;
                }
            }
        }
        /// <summary>
        /// Build expressions that are used when calling a .NET method with generic instance parameters, one expression for
        /// each required parameter.
        /// </summary>
        private static IList<AstExpression> CreateGenericInstanceCallArguments(ISourceLocation seqp, XReference member, MethodSource currentMethod, AssemblyCompiler compiler)
        {
            // Prepare
            var genericInstance = member as IXGenericInstance;
            if (genericInstance == null)
            {
#if DEBUG
                //Debugger.Launch();
#endif
                throw new CompilerException(string.Format("{0} is not a generic instance", member));
            }
            var count = genericInstance.GenericArguments.Count;
            var typeHelperType = compiler.GetDot42InternalType(InternalConstants.TypeHelperName).Resolve();

            // Foreach type argument
            var typeExpressions = new List<AstExpression>();
            for (var i = 0; i < count; i++)
            {
                var argType = genericInstance.GenericArguments[i];
                var typeExpr = LoadTypeForGenericInstance(seqp, currentMethod, argType, compiler, typeHelperType, compiler.Module.TypeSystem, 
                                                          TypeConversion.EnsureTrueOrMarkerType);
                typeExpressions.Add(typeExpr);
            }

            bool isMethod = member is XMethodReference;
            bool buildArray = count > (isMethod ? InternalConstants.GenericMethodParametersAsArrayThreshold 
                                                : InternalConstants.GenericTypeParametersAsArrayThreshold);
            if (buildArray)
            {
                //TODO: when we can determine that all expressions just load our classes generic instance (array) field,
                //      and extract all values in sequence, we should shortcut and just return a load of the field,
                //      instead of unpacking and re-packing each value, putting pressure on the garbage collector
                //      in the process. This is not a huge problem any longer, as we do not use arrays as often
                //      as we used to. Nevertheless, where arrays are used, possible re-use should be faily common,
                //      e.g. when instatiating nested classes or invoking static methods.
                var elementType = compiler.Module.TypeSystem.Type;
                return new [] { new AstExpression(seqp, AstCode.InitArrayFromArguments, new XArrayType(elementType), typeExpressions) { ExpectedType = new XArrayType(elementType) }};
            }
            else
            {
                return typeExpressions;
            }
        }
        void ProcessArgument(AstExpression callNode, XMethodReference methodRef, int argumentIndex, MethodSource currentMethod, XModule assembly)
        {
            var node = callNode.Arguments[argumentIndex];

            // Should we do something?
            switch (node.Code)
            {
            case AstCode.Ldloca:     // Parameter
            case AstCode.AddressOf:  // Local variable
            case AstCode.Ldflda:     // Instance field
            case AstCode.Ldsflda:    // Static field
            case AstCode.Ldelema:    // Array
                break;

            case AstCode.Ldloc:
                if (!node.MatchThis() || !currentMethod.IsDotNet)
                {
                    return;
                }
                break;

            default:
                return;
            }

            // Process argument
            var method         = methodRef.Resolve();
            var argIsThis      = !method.IsStatic && (argumentIndex == 0);
            var parameterIndex = method.IsStatic ? argumentIndex : argumentIndex - 1;
            var parameter      = argIsThis ? null : method.Parameters[parameterIndex];
            var argType        = argIsThis ? method.DeclaringType : parameter.ParameterType;
            //var argAttrs = argIsThis ? ParameterAttributes.None : parameter.Attributes;
            var argIsByRef         = argType.IsByReference;
            var argIsOut           = argIsThis ? false : argIsByRef && (parameter.Kind == XParameterKind.Output); // argIsByRef && argAttrs.HasFlag(ParameterAttributes.Out);
            var argIsGenByRefParam = argIsByRef && argType.ElementType.IsGenericParameter;

            switch (node.Code)
            {
            case AstCode.Ldloca:     // Parameter
            {
                var variable = ((AstVariable)node.Operand);
                if (variable.Type.IsPrimitive || argIsByRef)
                {
                    // Box first
                    var ldloc = new AstExpression(node.SourceLocation, AstCode.Ldloc, node.Operand)
                    {
                        InferredType = variable.Type
                    };
                    if (argIsByRef)
                    {
                        var stloc = new AstExpression(node.SourceLocation, AstCode.Stloc, node.Operand)
                        {
                            InferredType = variable.Type
                        };
                        stloc.Arguments.Add(GetValueOutOfByRefArray(node, variable.Type, argIsGenByRefParam, assembly));
                        ConvertToByRefArray(node, variable.Type, ldloc, stloc, argIsOut, argIsGenByRefParam, argType.ElementType, assembly);
                    }
                    else
                    {
                        ConvertToBox(node, variable.Type, ldloc);
                    }
                }
                else if (variable.Type.IsGenericParameter)
                {
                    // Convert to ldarg
                    var ldloc = new AstExpression(node.SourceLocation, AstCode.Ldloc, node.Operand)
                    {
                        InferredType = variable.Type
                    };
                    callNode.Arguments[argumentIndex] = ldloc;
                }
            }
            break;

            case AstCode.Ldloc:     // this
            {
                var variable = ((AstVariable)node.Operand);
                if (argIsThis && (variable.Type.IsByReference))
                {
                    node.SetType(variable.Type.ElementType);
                }
                else if (argIsByRef)
                {
                    var ldclone     = new AstExpression(node);
                    var stExpr      = new AstExpression(node.SourceLocation, AstCode.Nop, null);
                    var elementType = variable.Type;
                    if (elementType.IsByReference)
                    {
                        elementType = elementType.ElementType;
                    }
                    ConvertToByRefArray(node, elementType, ldclone, stExpr, argIsOut, argIsGenByRefParam, argType.ElementType, assembly);
                }
            }
            break;

            case AstCode.AddressOf:     // Local variable
            {
                var arg     = node.Arguments[0];
                var type    = arg.GetResultType();
                var typeDef = type.Resolve();
                if (typeDef.IsPrimitive)
                {
                    if (argIsByRef)
                    {
                        throw new CompilerException("Unsupported use of AddressOf by byref argument");
                    }
                    else
                    {
                        ConvertToBox(node, type, arg);
                    }
                }
            }
            break;

            case AstCode.Ldflda:     // Instance field
            case AstCode.Ldsflda:    // Static field
            {
                var fieldRef = (XFieldReference)node.Operand;
                var field    = fieldRef.Resolve();
                if (field.FieldType.IsPrimitive || argIsByRef)
                {
                    // Box first
                    var ldfldCode = (node.Code == AstCode.Ldflda) ? AstCode.Ldfld : AstCode.Ldsfld;
                    var ldfld     = new AstExpression(node.SourceLocation, ldfldCode, node.Operand)
                    {
                        InferredType = field.FieldType
                    };
                    ldfld.Arguments.AddRange(node.Arguments);
                    if (argIsByRef)
                    {
                        var stfldCode = (node.Code == AstCode.Ldflda) ? AstCode.Stfld : AstCode.Stsfld;
                        var stfld     = new AstExpression(node.SourceLocation, stfldCode, node.Operand)
                        {
                            InferredType = field.FieldType
                        };
                        stfld.Arguments.AddRange(node.Arguments);                                                          // instance
                        stfld.Arguments.Add(GetValueOutOfByRefArray(node, field.FieldType, argIsGenByRefParam, assembly)); // value
                        ConvertToByRefArray(node, field.FieldType, ldfld, stfld, argIsOut, argIsGenByRefParam, argType.ElementType, assembly);
                    }
                    else
                    {
                        ConvertToBox(node, field.FieldType, ldfld);
                    }
                }
            }
            break;

            case AstCode.Ldelema:     // Array element
            {
                var array     = node.Arguments[0];
                var arrayType = array.GetResultType();
                var type      = arrayType.ElementType;
                if (type.IsPrimitive || argIsByRef)
                {
                    // Box first
                    var ldElemCode = type.GetLdElemCode();
                    var ldelem     = new AstExpression(node.SourceLocation, ldElemCode, node.Operand)
                    {
                        InferredType = type
                    };
                    ldelem.Arguments.AddRange(node.Arguments);
                    if (argIsByRef)
                    {
                        var stelemCode = type.GetStElemCode();
                        var stelem     = new AstExpression(node.SourceLocation, stelemCode, node.Operand)
                        {
                            InferredType = type
                        };
                        stelem.Arguments.AddRange(node.Arguments);
                        stelem.Arguments.Add(GetValueOutOfByRefArray(node, type, argIsGenByRefParam, assembly));
                        ConvertToByRefArray(node, type, ldelem, stelem, argIsOut, argIsGenByRefParam, argType.ElementType, assembly);
                    }
                    else
                    {
                        ConvertToBox(node, type, ldelem);
                    }
                }
            }
            break;
            }
        }
        /// <summary>
        /// Create an expression that loads the given type at runtime.
        /// </summary>
        private static AstExpression LoadTypeForGenericInstance(ISourceLocation seqp, MethodSource currentMethod, 
                    XTypeReference type, AssemblyCompiler compiler, XTypeDefinition typeHelperType, XTypeSystem typeSystem, 
                    TypeConversion typeConversion, XGenericInstanceType typeGenericArguments=null)
        {
            if (type.IsArray)
            {
                // Array type
                var arrayType = (XArrayType)type;
                // Load element type
                var prefix = LoadTypeForGenericInstance(seqp, currentMethod, ((XArrayType)type).ElementType, compiler, typeHelperType, typeSystem, typeConversion);
                // Convert to array type
                if (arrayType.Dimensions.Count() == 1)
                {
                    var giCreateArray = typeHelperType.Methods.Single(x => (x.Name == "Array") && (x.Parameters.Count == 1));
                    return new AstExpression(seqp, AstCode.Call, giCreateArray, prefix) { ExpectedType = typeSystem.Type };
                }
                else
                {
                    var giCreateArray = typeHelperType.Methods.Single(x => (x.Name == "Array") && (x.Parameters.Count == 2));
                    var dimensionsExpr = new AstExpression(seqp, AstCode.Ldc_I4, arrayType.Dimensions.Count()) { ExpectedType = typeSystem.Int };
                    return new AstExpression(seqp, AstCode.Call, giCreateArray, prefix, dimensionsExpr) { ExpectedType = typeSystem.Type };
                }
            }

            var gp = type as XGenericParameter;
            if (gp != null)
            {
                AstExpression loadExpr;
                if (gp.Owner is XTypeReference)
                {
                    // Class type parameter
                    var owner = (XTypeReference)gp.Owner;
                    if (owner.GetElementType().Resolve().HasDexImportAttribute())
                    {
                        // Imported type
                        return new AstExpression(seqp, AstCode.TypeOf, typeSystem.Object) { ExpectedType = typeSystem.Type };
                    }
                    if (currentMethod.IsClassCtor)
                    {
                        // Class ctor's cannot have type information.
                        // Return Object instead
                        if(currentMethod.IsDotNet && !currentMethod.ILMethod.DeclaringType.HasSuppressMessageAttribute("StaticConstructorUsesGenericParameter"))
                        {
                            var msg = "Class (static) constructor of '{0}' tries to use generic parameter. This will always yield Object. " +
                                      "You can suppress this warning with a [SuppressMessage(\"dot42\", \"StaticConstructorUsesGenericParameter\")] " +
                                      "attribute on the class.";

                            if(seqp != null && seqp.Document != null)
                                DLog.Warning(DContext.CompilerCodeGenerator, seqp.Document, seqp.StartColumn,seqp.StartLine, msg, currentMethod.DeclaringTypeFullName);
                            else
                                DLog.Warning(DContext.CompilerCodeGenerator, msg, currentMethod.DeclaringTypeFullName);
                        }
                        return new AstExpression(seqp, AstCode.TypeOf, typeSystem.Object) { ExpectedType = typeSystem.Type };
                    }
                    loadExpr = currentMethod.IsStatic ?
                        LoadStaticClassGenericArgument(seqp, typeSystem, currentMethod.Method, gp.Position) :
                        LoadInstanceClassGenericArgument(seqp, typeSystem, currentMethod.Method.DeclaringType, gp.Position);
                }
                else
                {
                    // Method type parameter
                    var owner = (XMethodReference)gp.Owner;
                    if (owner.GetElementMethod().Resolve().DeclaringType.HasDexImportAttribute())
                    {
                        // Imported type
                        return LoadTypeForGenericInstance(seqp, currentMethod, type.Module.TypeSystem.Object, compiler, typeHelperType, typeSystem, typeConversion);
                    }
                    loadExpr = LoadMethodGenericArgument(seqp, typeSystem, currentMethod.Method, gp.Position);
                }

                if (typeConversion == TypeConversion.EnsureRuntimeType)
                    return EnsureGenericRuntimeType(loadExpr, typeSystem, typeHelperType);
                else
                    return loadExpr;
            }

            if (type is XTypeSpecification)
            {
                var typeSpec = (XTypeSpecification)type;
                var git = type as XGenericInstanceType;
                var baseType = LoadTypeForGenericInstance(seqp, currentMethod, typeSpec.ElementType, compiler, typeHelperType, typeSystem, typeConversion, git);

                if (typeConversion != TypeConversion.EnsureTrueOrMarkerType || typeSpec.GetElementType().IsNullableT())
                    return baseType;

                // Use the element type and make a generic proxy with the generic arguments.
                var parameters = CreateGenericInstanceCallArguments(seqp, git, currentMethod, compiler);
                if (parameters.Count == 1 && parameters[0].GetResultType().IsArray)
                {
                    // array type call.
                    var method = typeHelperType.Methods.Single(m => m.Name == "GetGenericInstanceType" && m.Parameters.Count == 2 && m.Parameters[1].ParameterType.IsArray);
                    return new AstExpression(seqp, AstCode.Call, method, baseType, parameters[0]);
                }
                else
                {
                    parameters.Insert(0, baseType);
                    var method = typeHelperType.Methods.Single(m => m.Name == "GetGenericInstanceType" && m.Parameters.Count == parameters.Count && !m.Parameters[1].ParameterType.IsArray);
                    return new AstExpression(seqp, AstCode.Call, method, parameters.ToArray());
                }
            }


            if (typeConversion == TypeConversion.EnsureTrueOrMarkerType && type.GetElementType().IsNullableT())
            {
                if (typeGenericArguments != null)
                {
                    var underlying = typeGenericArguments.GenericArguments[0];
                    var code = underlying.IsPrimitive ? AstCode.BoxedTypeOf : AstCode.NullableTypeOf;
                    return new AstExpression(seqp, code, underlying) { ExpectedType = typeSystem.Type };
                }
                // if typeGenericArguments is null, this is a generic definition, e.g. typeof(Nullable<>).
            }

            // Plain type reference or definition
            return new AstExpression(seqp, AstCode.TypeOf, type) { ExpectedType = typeSystem.Type };
        }
Beispiel #45
0
 internal MethodBody(MethodSource method)
 {
     this.method = method;
 }
        /// <summary>
        /// Optimize expressions
        /// </summary>
        public static void Convert(AstNode ast, MethodSource currentMethod, AssemblyCompiler compiler)
        {
            var typeSystem = compiler.Module.TypeSystem;

            // Expand typeof
            foreach (var node in ast.GetSelfAndChildrenRecursive<AstExpression>(x => x.Code == AstCode.TypeOf))
            {
                var type = (XTypeReference) node.Operand;
                var typeHelperType = compiler.GetDot42InternalType(InternalConstants.TypeHelperName).Resolve();
                var loadExpr = LoadTypeForGenericInstance(node.SourceLocation, currentMethod, type, compiler, typeHelperType, typeSystem, TypeConversion.EnsureTrueOrMarkerType);
                node.CopyFrom(loadExpr);
            }

            // Expand instanceOf
            foreach (var node in ast.GetSelfAndChildrenRecursive<AstExpression>(x => x.Code == AstCode.SimpleInstanceOf))
            {
                var type = (XTypeReference)node.Operand;
                var gp = type as XGenericParameter;
                if (gp == null) continue;

                var typeHelperType = compiler.GetDot42InternalType(InternalConstants.TypeHelperName).Resolve();
                var loadExpr = LoadTypeForGenericInstance(node.SourceLocation, currentMethod, type, compiler, typeHelperType, typeSystem, TypeConversion.EnsureRuntimeType);
                //// both types are boxed, no need for conversion.
                var typeType = compiler.GetDot42InternalType("System", "Type").Resolve();
                var isInstanceOfType = typeType.Methods.Single(n => n.Name == "JavaIsInstance" && n.Parameters.Count == 1);
                var call = new AstExpression(node.SourceLocation, AstCode.Call, isInstanceOfType, loadExpr, node.Arguments[0]);
                node.CopyFrom(call);
            }

            // Expand newarr
            foreach (var node in ast.GetSelfAndChildrenRecursive<AstExpression>(x => x.Code == AstCode.Newarr))
            {
                var type = (XTypeReference)node.Operand;
                if (!type.IsDefinitionOrReferenceOrPrimitive())
                {
                    // Resolve type to a Class<?>
                    var typeHelperType = compiler.GetDot42InternalType(InternalConstants.TypeHelperName).Resolve();
                    // while having primitive arrays for primitive types would be nice, a lot of boxing and unboxing
                    // would be needed. only for-primitive-specialized generic classes we could optimize this.
                    var ldType = LoadTypeForGenericInstance(node.SourceLocation, currentMethod, type, compiler, typeHelperType, typeSystem, TypeConversion.EnsureRuntimeType);
                    var newInstanceExpr = new AstExpression(node.SourceLocation, AstCode.ArrayNewInstance, null, ldType, node.Arguments[0]) { ExpectedType = typeSystem.Object };
                    var arrayType = new XArrayType(type);
                    var cast = new AstExpression(node.SourceLocation, AstCode.SimpleCastclass, arrayType, newInstanceExpr) { ExpectedType = arrayType };
                    node.CopyFrom(cast);
                }
            }

            // Add generic instance call arguments
            foreach (var node in ast.GetSelfAndChildrenRecursive<AstExpression>(x => x.Code.IsCall()))
            {
                var method = (XMethodReference)node.Operand;
                if (method.DeclaringType.IsArray)
                    continue;
                XMethodDefinition methodDef;
                if (!method.TryResolve(out methodDef)) 
                    continue;
                if (methodDef.HasDexNativeAttribute())
                    continue;

                if (methodDef.NeedsGenericInstanceTypeParameter)
                {
                    // Add generic instance type parameter value
                    var arg = CreateGenericInstanceCallArguments(node.SourceLocation, method.DeclaringType, currentMethod, compiler);
                    node.Arguments.AddRange(arg);
                    node.GenericInstanceArgCount += arg.Count;
                }

                if (methodDef.NeedsGenericInstanceMethodParameter)
                {
                    // Add generic instance method parameter
                    var arg = CreateGenericInstanceCallArguments(node.SourceLocation, method, currentMethod, compiler);
                    node.Arguments.AddRange(arg);
                    node.GenericInstanceArgCount += arg.Count;
                }
            }

            // Add generic instance Delegate arguments for static methods.
            foreach (var node in ast.GetSelfAndChildrenRecursive<AstExpression>(x => x.Code == AstCode.Delegate))
            {
                var delegateInfo = (Tuple<XTypeDefinition, XMethodReference>)node.Operand;

                var genMethodDef = delegateInfo.Item2 as IXGenericInstance;
                var genTypeDef = delegateInfo.Item2.DeclaringType as IXGenericInstance;

                // Add generic instance type parameter value, if method is static
                if (genTypeDef != null && delegateInfo.Item2.Resolve().IsStatic)
                {
                    var arg = CreateGenericInstanceCallArguments(node.SourceLocation, delegateInfo.Item2.DeclaringType, currentMethod, compiler);
                    node.Arguments.AddRange(arg);
                    node.GenericInstanceArgCount += arg.Count;
                }

                // add generic method type parameter value.
                if (genMethodDef != null)
                {
                    var arg = CreateGenericInstanceCallArguments(node.SourceLocation, delegateInfo.Item2, currentMethod, compiler);
                    node.Arguments.AddRange(arg);
                    node.GenericInstanceArgCount += arg.Count;
                }
            }

            // Convert NewObj when needed
            foreach (var node in ast.GetSelfAndChildrenRecursive<AstExpression>(x => x.Code == AstCode.Newobj))
            {
                var ctorRef = (XMethodReference)node.Operand;
                var declaringType = ctorRef.DeclaringType;
                if (declaringType.IsArray)
                {
                    // New multi dimensional array
                    // Get element type
                    var elemType = ((XArrayType) declaringType).ElementType;
                    var typeExpr = new AstExpression(node.SourceLocation, AstCode.TypeOf, elemType);

                    // Create dimensions array
                    var intArrayType = new XArrayType(typeSystem.Int);
                    var dimArrayExpr = new AstExpression(node.SourceLocation, AstCode.InitArrayFromArguments, intArrayType, node.Arguments).SetType(intArrayType);

                    // Call java.lang.reflect.Array.newInstance(type, int[])
                    var newInstanceExpr = new AstExpression(node.SourceLocation, AstCode.ArrayNewInstance2, null, typeExpr, dimArrayExpr).SetType(typeSystem.Object);

                    // Cast to correct type
                    var cast = new AstExpression(node.SourceLocation, AstCode.SimpleCastclass, declaringType, newInstanceExpr).SetType(declaringType);

                    // Replace node
                    node.CopyFrom(cast);
                }
                else
                {
                    // Normal "new object"
                    XMethodDefinition ctorDef;
                    if (ctorRef.TryResolve(out ctorDef) && ctorDef.NeedsGenericInstanceTypeParameter)
                    {
                        // Add generic instance type parameter value
                        var arg = CreateGenericInstanceCallArguments(node.SourceLocation, ctorRef.DeclaringType, currentMethod, compiler);
                        node.Arguments.AddRange(arg);
                        node.GenericInstanceArgCount += arg.Count;
                    }
                }
            }
        }
Beispiel #47
0
 /// <summary>
 /// Returns the hash code of this object.
 /// </summary>
 /// <returns>The hash code of this object.</returns>
 public override int GetHashCode() =>
 MethodSource.GetHashCode() ^ IndexType.GetHashCode();
Beispiel #48
0
        internal BreakpointHandle ResolveBreakpoint(Breakpoint breakpoint)
        {
            if (!module.IsLoaded)
                return null;

            if ((function == null) && (source == null)) {
                if (file != null) {
                    source = file.FindMethod (line);
                } else {
                    throw new TargetException (TargetError.LocationInvalid);
                }

                if ((source != null) && source.IsManaged)
                    function = source.Function;
            }

            if (function != null)
                return function.GetBreakpointHandle (breakpoint, line, column);

            if ((source == null) || source.IsManaged)
                throw new TargetException (TargetError.LocationInvalid);

            TargetAddress address = GetAddress ();
            if (!address.IsNull)
                return new AddressBreakpointHandle (breakpoint, address);

            return null;
        }
Beispiel #49
0
        protected override bool DoResolve(ScriptingContext context)
        {
            int line = -1;
            int pos = Argument.IndexOf (':');
            if (pos >= 0) {
                string filename = Argument.Substring (0, pos);
                try {
                    line = (int) UInt32.Parse (Argument.Substring (pos+1));
                } catch {
                    throw new ScriptingException ("Expected filename:line");
                }

                return FindFile (context, filename, line);
            }

            if (Argument == "") {
                StackFrame frame = context.CurrentFrame;

                if (frame.SourceAddress == null)
                    return false;

                if (frame.SourceLocation != null)
                    location = frame.SourceLocation;
                else
                    address = frame.SourceAddress;

                return true;
            }

            try {
                line = (int) UInt32.Parse (Argument);
            } catch {
            }

            if (line != -1) {
                location = context.CurrentLocation;
                if (location.FileName == null)
                    throw new ScriptingException (
                        "Location doesn't have any source code.");

                return FindFile (context, location.FileName, line);
            }

            MethodExpression mexpr;
            try {
                Expression expr = ParseExpression (context);
                if (expr == null)
                    return false;

                mexpr = expr.ResolveMethod (context, type);
            } catch {
                mexpr = null;
            }

            if (mexpr != null) {
                TargetFunctionType func;
                try {
                    func = mexpr.EvaluateMethod (context, type, null);
                } catch {
                    func = null;
                }

                if (func != null)
                    method = func.GetSourceCode ();

                location = mexpr.EvaluateSource (context);
            } else
                location = context.FindMethod (Argument);

            if (location == null)
                throw new ScriptingException (
                    "Location doesn't have any source code.");

            return true;
        }
Beispiel #50
0
 public SourceLocation(MethodSource source, SourceFile file, int line)
     : this(source, file, line, -1)
 {
 }
        /// <summary>
        /// Build expressions that are used when calling a .NET method with generic instance parameters, one expression for
        /// each required parameter.
        /// </summary>
        private static IList <AstExpression> CreateGenericInstanceCallArguments(ISourceLocation seqp, XReference member, MethodSource currentMethod, AssemblyCompiler compiler)
        {
            // Prepare
            var genericInstance = member as IXGenericInstance;

            if (genericInstance == null)
            {
#if DEBUG
                //Debugger.Launch();
#endif
                throw new CompilerException(string.Format("{0} is not a generic instance", member));
            }
            var count          = genericInstance.GenericArguments.Count;
            var typeHelperType = compiler.GetDot42InternalType(InternalConstants.TypeHelperName).Resolve();

            // Foreach type argument
            var typeExpressions = new List <AstExpression>();
            for (var i = 0; i < count; i++)
            {
                var argType  = genericInstance.GenericArguments[i];
                var typeExpr = LoadTypeForGenericInstance(seqp, currentMethod, argType, compiler, typeHelperType, compiler.Module.TypeSystem,
                                                          TypeConversion.EnsureTrueOrMarkerType);
                typeExpressions.Add(typeExpr);
            }

            bool isMethod   = member is XMethodReference;
            bool buildArray = count > (isMethod ? InternalConstants.GenericMethodParametersAsArrayThreshold
                                                : InternalConstants.GenericTypeParametersAsArrayThreshold);
            if (buildArray)
            {
                //TODO: when we can determine that all expressions just load our classes generic instance (array) field,
                //      and extract all values in sequence, we should shortcut and just return a load of the field,
                //      instead of unpacking and re-packing each value, putting pressure on the garbage collector
                //      in the process. This is not a huge problem any longer, as we do not use arrays as often
                //      as we used to. Nevertheless, where arrays are used, possible re-use should be faily common,
                //      e.g. when instatiating nested classes or invoking static methods.
                var elementType = compiler.Module.TypeSystem.Type;
                return(new [] { new AstExpression(seqp, AstCode.InitArrayFromArguments, new XArrayType(elementType), typeExpressions)
                                {
                                    ExpectedType = new XArrayType(elementType)
                                } });
            }
            else
            {
                return(typeExpressions);
            }
        }
        public static void Convert(AstBlock ast, MethodSource currentMethod, AssemblyCompiler compiler)
        {
            var setInstructionTarget = new AstGeneratedVariable(DebuggerConstants.SetNextInstructionVariableName, null, true)
            {
                Type = compiler.Module.TypeSystem.Bool
            };

            int labelCount = 0;
            var initExpr = new AstExpression(AstNode.NoSource, AstCode.Stloc, setInstructionTarget,
                                                    new AstExpression(AstNode.NoSource, AstCode.Ldnull, null)
                                                             .SetType(compiler.Module.TypeSystem.Int));

            int lastBaseCtorCall = -1;

            // can't jump before base-class constructor call.
            if (currentMethod.IsCtor)
                lastBaseCtorCall = FindLastCtorCall(ast);

            ISourceLocation currentLoc = null;
            
            foreach (var block in ast.GetSelfAndChildrenRecursive<AstBlock>())
            {
                if (block.EntryGoto != null) // only handle simple cases atm.
                    return;

                var body = block.Body;
                AstLabel label = null;
                int firstValidExpression = -1;
                bool lastExprWasCall = false;

                var startIdx = lastBaseCtorCall == -1?0:lastBaseCtorCall + 1;
                lastBaseCtorCall = -1;

                for (int idx = startIdx; idx < body.Count; ++idx)
                {
                    var expr = body[idx] as AstExpression;
                    if(expr == null)
                        continue;

                    if (expr.SourceLocation == null)
                        continue;

                    if (expr.SourceLocation.Equals(currentLoc) && !lastExprWasCall)
                        continue;

                    currentLoc = expr.SourceLocation;

                    lastExprWasCall = expr.Code.IsCall();

                    if (firstValidExpression == -1)
                    {
                        firstValidExpression = idx;
                        continue;
                    }

                    AddJumpInstruction(body, currentLoc, setInstructionTarget, ref idx, 
                                       ref label, firstValidExpression, initExpr, ref labelCount);
                }

                //if (!lastExprWasRet && firstValidExpression != -1)
                //{
                //    int idx = body.Count;
                //    AddJumpInstruction(body, currentLoc, setInstructionTarget, ref idx,
                //                       ref label, firstValidExpression, initExpr, ref labelCount);
                //}
            }
        }
        /// <summary>
        /// Optimize expressions
        /// </summary>
        public static void Convert(AstNode ast, MethodSource currentMethod, AssemblyCompiler compiler)
        {
            var typeSystem = compiler.Module.TypeSystem;

            // Expand typeof
            foreach (var node in ast.GetSelfAndChildrenRecursive <AstExpression>(x => x.Code == AstCode.TypeOf))
            {
                var type           = (XTypeReference)node.Operand;
                var typeHelperType = compiler.GetDot42InternalType(InternalConstants.TypeHelperName).Resolve();
                var loadExpr       = LoadTypeForGenericInstance(node.SourceLocation, currentMethod, type, compiler, typeHelperType, typeSystem, TypeConversion.EnsureTrueOrMarkerType);
                node.CopyFrom(loadExpr);
            }

            // Expand instanceOf
            foreach (var node in ast.GetSelfAndChildrenRecursive <AstExpression>(x => x.Code == AstCode.SimpleInstanceOf))
            {
                var type = (XTypeReference)node.Operand;
                var gp   = type as XGenericParameter;
                if (gp == null)
                {
                    continue;
                }

                var typeHelperType = compiler.GetDot42InternalType(InternalConstants.TypeHelperName).Resolve();
                var loadExpr       = LoadTypeForGenericInstance(node.SourceLocation, currentMethod, type, compiler, typeHelperType, typeSystem, TypeConversion.EnsureRuntimeType);
                //// both types are boxed, no need for conversion.
                var typeType         = compiler.GetDot42InternalType("System", "Type").Resolve();
                var isInstanceOfType = typeType.Methods.Single(n => n.Name == "JavaIsInstance" && n.Parameters.Count == 1);
                var call             = new AstExpression(node.SourceLocation, AstCode.Call, isInstanceOfType, loadExpr, node.Arguments[0]);
                node.CopyFrom(call);
            }

            // Expand newarr
            foreach (var node in ast.GetSelfAndChildrenRecursive <AstExpression>(x => x.Code == AstCode.Newarr))
            {
                var type = (XTypeReference)node.Operand;
                if (!type.IsDefinitionOrReferenceOrPrimitive())
                {
                    // Resolve type to a Class<?>
                    var typeHelperType = compiler.GetDot42InternalType(InternalConstants.TypeHelperName).Resolve();
                    // while having primitive arrays for primitive types would be nice, a lot of boxing and unboxing
                    // would be needed. only for-primitive-specialized generic classes we could optimize this.
                    var ldType          = LoadTypeForGenericInstance(node.SourceLocation, currentMethod, type, compiler, typeHelperType, typeSystem, TypeConversion.EnsureRuntimeType);
                    var newInstanceExpr = new AstExpression(node.SourceLocation, AstCode.ArrayNewInstance, null, ldType, node.Arguments[0])
                    {
                        ExpectedType = typeSystem.Object
                    };
                    var arrayType = new XArrayType(type);
                    var cast      = new AstExpression(node.SourceLocation, AstCode.SimpleCastclass, arrayType, newInstanceExpr)
                    {
                        ExpectedType = arrayType
                    };
                    node.CopyFrom(cast);
                }
            }

            // Add generic instance call arguments
            foreach (var node in ast.GetSelfAndChildrenRecursive <AstExpression>(x => x.Code.IsCall()))
            {
                var method = (XMethodReference)node.Operand;
                if (method.DeclaringType.IsArray)
                {
                    continue;
                }
                XMethodDefinition methodDef;
                if (!method.TryResolve(out methodDef))
                {
                    continue;
                }
                if (methodDef.HasDexNativeAttribute())
                {
                    continue;
                }

                if (methodDef.NeedsGenericInstanceTypeParameter)
                {
                    // Add generic instance type parameter value
                    var arg = CreateGenericInstanceCallArguments(node.SourceLocation, method.DeclaringType, currentMethod, compiler);
                    node.Arguments.AddRange(arg);
                    node.GenericInstanceArgCount += arg.Count;
                }

                if (methodDef.NeedsGenericInstanceMethodParameter)
                {
                    // Add generic instance method parameter
                    var arg = CreateGenericInstanceCallArguments(node.SourceLocation, method, currentMethod, compiler);
                    node.Arguments.AddRange(arg);
                    node.GenericInstanceArgCount += arg.Count;
                }
            }

            // Add generic instance Delegate arguments for static methods.
            foreach (var node in ast.GetSelfAndChildrenRecursive <AstExpression>(x => x.Code == AstCode.Delegate))
            {
                var delegateInfo = (Tuple <XTypeDefinition, XMethodReference>)node.Operand;

                var genMethodDef = delegateInfo.Item2 as IXGenericInstance;
                var genTypeDef   = delegateInfo.Item2.DeclaringType as IXGenericInstance;

                // Add generic instance type parameter value, if method is static
                if (genTypeDef != null && delegateInfo.Item2.Resolve().IsStatic)
                {
                    var arg = CreateGenericInstanceCallArguments(node.SourceLocation, delegateInfo.Item2.DeclaringType, currentMethod, compiler);
                    node.Arguments.AddRange(arg);
                    node.GenericInstanceArgCount += arg.Count;
                }

                // add generic method type parameter value.
                if (genMethodDef != null)
                {
                    var arg = CreateGenericInstanceCallArguments(node.SourceLocation, delegateInfo.Item2, currentMethod, compiler);
                    node.Arguments.AddRange(arg);
                    node.GenericInstanceArgCount += arg.Count;
                }
            }

            // Convert NewObj when needed
            foreach (var node in ast.GetSelfAndChildrenRecursive <AstExpression>(x => x.Code == AstCode.Newobj))
            {
                var ctorRef       = (XMethodReference)node.Operand;
                var declaringType = ctorRef.DeclaringType;
                if (declaringType.IsArray)
                {
                    // New multi dimensional array
                    // Get element type
                    var elemType = ((XArrayType)declaringType).ElementType;
                    var typeExpr = new AstExpression(node.SourceLocation, AstCode.TypeOf, elemType);

                    // Create dimensions array
                    var intArrayType = new XArrayType(typeSystem.Int);
                    var dimArrayExpr = new AstExpression(node.SourceLocation, AstCode.InitArrayFromArguments, intArrayType, node.Arguments).SetType(intArrayType);

                    // Call java.lang.reflect.Array.newInstance(type, int[])
                    var newInstanceExpr = new AstExpression(node.SourceLocation, AstCode.ArrayNewInstance2, null, typeExpr, dimArrayExpr).SetType(typeSystem.Object);

                    // Cast to correct type
                    var cast = new AstExpression(node.SourceLocation, AstCode.SimpleCastclass, declaringType, newInstanceExpr).SetType(declaringType);

                    // Replace node
                    node.CopyFrom(cast);
                }
                else
                {
                    // Normal "new object"
                    XMethodDefinition ctorDef;
                    if (ctorRef.TryResolve(out ctorDef) && ctorDef.NeedsGenericInstanceTypeParameter)
                    {
                        // Add generic instance type parameter value
                        var arg = CreateGenericInstanceCallArguments(node.SourceLocation, ctorRef.DeclaringType, currentMethod, compiler);
                        node.Arguments.AddRange(arg);
                        node.GenericInstanceArgCount += arg.Count;
                    }
                }
            }
        }
Beispiel #54
0
 public SourceLocation(MethodSource source)
     : this(source, source.SourceFile, -1, -1)
 {
 }
Beispiel #55
0
 /// <summary>
 /// Generate an Invoke opcode.
 /// </summary>
 internal static RCode Invoke(this XMethodDefinition targetMethod, XMethodReference targetMethodRef, MethodSource currentMethod, bool isSpecial = false)
 {
     if (targetMethod != null)
     {
         if (targetMethod.DeclaringType.IsDelegate())
         {
             return RCode.Invoke_interface;
         }
         if (targetMethod.IsStatic || targetMethod.IsAndroidExtension)
         {
             return RCode.Invoke_static;
         }
         if ((currentMethod != null) && targetMethod.UseInvokeSuper(currentMethod.Method))
         {
             return RCode.Invoke_super;
         }
         if (isSpecial && !targetMethod.IsConstructor && (currentMethod != null) && targetMethod.DeclaringType.IsBaseOf(currentMethod.Method.DeclaringType))
         {
             return RCode.Invoke_super;
         }
         if (targetMethod.UseInvokeInterface)
         {
             return RCode.Invoke_interface;                    
         }
         if (targetMethod.IsDirect)
         {
             return RCode.Invoke_direct;
         }
         if (targetMethod.DeclaringType.IsInterface)
         {
             return RCode.Invoke_interface;
         }
     }
     if (targetMethodRef != null)
     {
         if (!targetMethodRef.HasThis)
         {
             return RCode.Invoke_static;
         }
         switch (targetMethodRef.Name)
         {
             case "<init>":
             case "<clinit>":
             case ".ctor":
             case ".cctor":
                 return RCode.Invoke_direct;                        
         }
     }
     return RCode.Invoke_virtual;
 }
Beispiel #56
0
        /// <summary>
        /// Create a method body for the given method.
        /// </summary>
        internal static MethodBody TranslateToRL(AssemblyCompiler compiler, DexTargetPackage targetPackage, MethodSource source, DexLib.MethodDefinition dmethod, 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);

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

                // Should we add return_void?
                if (source.ReturnsVoid)
                {
                    var instructions = rlBody.Instructions;
                    if ((instructions.Count == 0) || (instructions.Last().Code != RCode.Return_void))
                    {
                        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);
            }
        }
Beispiel #57
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));
            }
        }
Beispiel #58
0
 internal MethodBody(MethodSource method)
 {
     this.method = method;
 }
        /// <summary>
        /// Perform all dot42 related Ast conversions.
        /// </summary>
        public static void Convert(DecompilerContext context, AstBlock ast, MethodSource currentMethod, AssemblyCompiler compiler, StopAstConversion stop = StopAstConversion.None)
        {
            if (ast.IsOptimizedForTarget)
            {
                return;
            }
#if DEBUG
            //Debugger.Launch();
            if ((currentMethod.Method != null) && (currentMethod.Method.Name.Equals("runTest", StringComparison.OrdinalIgnoreCase)))
            {
                //Debugger.Launch();
            }
#endif

            IntPtrConverter.Convert(ast, compiler);
            if (stop == StopAstConversion.AfterIntPtrConverter)
            {
                return;
            }

            TypeOfConverter.Convert(ast, compiler);
            if (stop == StopAstConversion.AfterTypeOfConverter)
            {
                return;
            }

            // TODO: check if we actually need this optimizer, as we have a more throughoutful
            //       optimizer as the last step.
            BranchOptimizer.Convert(ast);
            if (stop == StopAstConversion.AfterBranchOptimizer)
            {
                return;
            }

            CompoundAssignmentConverter.Convert(ast);
            if (stop == StopAstConversion.AfterCompoundAssignmentConverter)
            {
                return;
            }

            // keep this order
            FixAsyncStateMachine.Convert(ast, currentMethod, compiler);
            if (stop == StopAstConversion.AfterFixAsyncStateMachine)
            {
                return;
            }

            InterlockedConverter.Convert(ast, currentMethod, compiler);
            if (stop == StopAstConversion.AfterInterlockedConverter)
            {
                return;
            }

            ByReferenceParamConverter.Convert(context, ast, compiler);
            if (stop == StopAstConversion.AfterByReferenceParamConverter)
            {
                return;
            }

            // end
            CompareUnorderedConverter.Convert(ast);
            if (stop == StopAstConversion.AfterCompareUnorderedConverter)
            {
                return;
            }

            EnumConverter.Convert(ast, compiler);
            if (stop == StopAstConversion.AfterEnumConverter)
            {
                return;
            }

            EnumOptimizer.Convert(ast, compiler);
            if (stop == StopAstConversion.AfterEnumOptimizer)
            {
                return;
            }

            // Keep this order
            NullableConverter.Convert(ast, compiler);
            if (stop == StopAstConversion.AfterNullableConverter)
            {
                return;
            }

            PrimitiveAddressOfConverter.Convert(ast, currentMethod, compiler);
            if (stop == StopAstConversion.AfterPrimitiveAddressOfConverter)
            {
                return;
            }

            StructCallConverter.Convert(ast, compiler);
            if (stop == StopAstConversion.AfterStructCallConverter)
            {
                return;
            }
            // end


            InitializeStructVariablesConverter.Convert(ast);
            if (stop == StopAstConversion.AfterInitializeStructVariablesConverter)
            {
                return;
            }

            DelegateConverter.Convert(ast);
            if (stop == StopAstConversion.AfterDelegateConverter)
            {
                return;
            }

            LdcWideConverter.Convert(ast);
            if (stop == StopAstConversion.AfterLdcWideConverter)
            {
                return;
            }

            LdLocWithConversionConverter.Convert(ast);
            if (stop == StopAstConversion.AfterLdLocWithConversionConverter)
            {
                return;
            }

            ConvertAfterLoadConversionConverter.Convert(ast);
            if (stop == StopAstConversion.AfterConvertAfterLoadConversionConverter)
            {
                return;
            }

            ConvertBeforeStoreConversionConverter.Convert(ast);
            if (stop == StopAstConversion.AfterConvertBeforeStoreConversionConverter)
            {
                return;
            }

            CleanupConverter.Convert(ast);
            if (stop == StopAstConversion.AfterCleanupConverter)
            {
                return;
            }

            GenericsConverter.Convert(ast, currentMethod, compiler.Module.TypeSystem);
            if (stop == StopAstConversion.AfterGenericsConverter)
            {
                return;
            }

            // Expand cast expressions
            CastConverter.Convert(ast, currentMethod, compiler);
            if (stop == StopAstConversion.AfterCastConverter)
            {
                return;
            }

            // Expand generic instance information
            GenericInstanceConverter.Convert(ast, currentMethod, compiler);
            if (stop == StopAstConversion.AfterGenericInstanceConverter)
            {
                return;
            }

            // run the branch optimizer again. (do we need the first invocation?)
            BranchOptimizer2.Convert(ast, compiler);
            if (stop == StopAstConversion.AfterBranchOptimizer2)
            {
                return;
            }
        }
        void ProcessArgument(AstExpression callNode, XMethodReference methodRef, int argumentIndex, MethodSource currentMethod, XModule assembly)
        {
            var node = callNode.Arguments[argumentIndex];

            // Should we do something?
            switch (node.Code)
            {
                case AstCode.Ldloca: // Parameter
                case AstCode.AddressOf: // Local variable
                case AstCode.Ldflda: // Instance field
                case AstCode.Ldsflda: // Static field
                case AstCode.Ldelema: // Array
                    break;
                case AstCode.Ldloc:
                    if (!node.MatchThis() || !currentMethod.IsDotNet)
                        return;
                    break;
                default:
                    return;
            }

            // Process argument
            var method = methodRef.Resolve();
            var argIsThis = !method.IsStatic && (argumentIndex == 0);
            var parameterIndex = method.IsStatic ? argumentIndex : argumentIndex - 1;
            var parameter = argIsThis ? null : method.Parameters[parameterIndex];
            var argType = argIsThis ? method.DeclaringType : parameter.ParameterType;
            //var argAttrs = argIsThis ? ParameterAttributes.None : parameter.Attributes;
            var argIsByRef = argType.IsByReference;
            var argIsOut = argIsThis ? false : argIsByRef && (parameter.Kind == XParameterKind.Output); // argIsByRef && argAttrs.HasFlag(ParameterAttributes.Out);
            var argIsGenByRefParam = argIsByRef && argType.ElementType.IsGenericParameter;
            switch (node.Code)
            {
                case AstCode.Ldloca: // Parameter
                    {
                        var variable = ((AstVariable)node.Operand);
                        if (variable.Type.IsPrimitive || argIsByRef)
                        {
                            // Box first
                            var ldloc = new AstExpression(node.SourceLocation, AstCode.Ldloc, node.Operand) { InferredType = variable.Type };
                            if (argIsByRef)
                            {
                                var stloc = new AstExpression(node.SourceLocation, AstCode.Stloc, node.Operand) { InferredType = variable.Type };
                                stloc.Arguments.Add(GetValueOutOfByRefArray(node, variable.Type, argIsGenByRefParam, assembly));
                                ConvertToByRefArray(node, variable.Type, ldloc, stloc, argIsOut, argIsGenByRefParam, assembly);
                            }
                            else
                            {
                                ConvertToBox(node, variable.Type, ldloc);
                            }
                        }
                        else if (variable.Type.IsGenericParameter)
                        {
                            // Convert to ldarg
                            var ldloc = new AstExpression(node.SourceLocation, AstCode.Ldloc, node.Operand) { InferredType = variable.Type };
                            callNode.Arguments[argumentIndex] = ldloc;
                        }
                    }
                    break;
                case AstCode.Ldloc: // this
                    {
                        var variable = ((AstVariable)node.Operand);
                        if (argIsThis && (variable.Type.IsByReference))
                        {
                            node.SetType(variable.Type.ElementType);
                        }
                        else if (argIsByRef)
                        {
                            var ldclone = new AstExpression(node);
                            var stExpr = new AstExpression(node.SourceLocation, AstCode.Nop, null);
                            var elementType = variable.Type;
                            if (elementType.IsByReference) elementType = elementType.ElementType;
                            ConvertToByRefArray(node, elementType, ldclone, stExpr, argIsOut, argIsGenByRefParam, assembly);
                        }
                    }
                    break;
                case AstCode.AddressOf: // Local variable
                    {
                        var arg = node.Arguments[0];
                        var type = arg.GetResultType();
                        var typeDef = type.Resolve();
                        if (typeDef.IsPrimitive)
                        {
                            if (argIsByRef)
                            {
                                throw new CompilerException("Unsupported use of AddressOf by byref argument");
                            }
                            else
                            {
                                ConvertToBox(node, type, arg);
                            }
                        }
                    }
                    break;
                case AstCode.Ldflda: // Instance field
                case AstCode.Ldsflda: // Static field
                    {
                        var fieldRef = (XFieldReference)node.Operand;
                        var field = fieldRef.Resolve();
                        if (field.FieldType.IsPrimitive || argIsByRef)
                        {
                            // Box first
                            var ldfldCode = (node.Code == AstCode.Ldflda) ? AstCode.Ldfld : AstCode.Ldsfld;
                            var ldfld = new AstExpression(node.SourceLocation, ldfldCode, node.Operand) { InferredType = field.FieldType };
                            ldfld.Arguments.AddRange(node.Arguments);
                            if (argIsByRef)
                            {
                                var stfldCode = (node.Code == AstCode.Ldflda) ? AstCode.Stfld : AstCode.Stsfld;
                                var stfld = new AstExpression(node.SourceLocation, stfldCode, node.Operand) { InferredType = field.FieldType };
                                stfld.Arguments.AddRange(node.Arguments); // instance
                                stfld.Arguments.Add(GetValueOutOfByRefArray(node, field.FieldType, argIsGenByRefParam, assembly)); // value
                                ConvertToByRefArray(node, field.FieldType, ldfld, stfld, argIsOut, argIsGenByRefParam, assembly);
                            }
                            else
                            {
                                ConvertToBox(node, field.FieldType, ldfld);
                            }
                        }
                    }
                    break;
                case AstCode.Ldelema: // Array element
                    {
                        var array = node.Arguments[0];
                        var arrayType = array.GetResultType();
                        var type = arrayType.ElementType;
                        if (type.IsPrimitive || argIsByRef)
                        {
                            // Box first
                            var ldElemCode = type.GetLdElemCode();
                            var ldelem = new AstExpression(node.SourceLocation, ldElemCode, node.Operand) { InferredType = type };
                            ldelem.Arguments.AddRange(node.Arguments);
                            if (argIsByRef)
                            {
                                var stelemCode = type.GetStElemCode();
                                var stelem = new AstExpression(node.SourceLocation, stelemCode, node.Operand) { InferredType = type };
                                stelem.Arguments.AddRange(node.Arguments);
                                stelem.Arguments.Add(GetValueOutOfByRefArray(node, type, argIsGenByRefParam, assembly));
                                ConvertToByRefArray(node, type, ldelem, stelem, argIsOut, argIsGenByRefParam, assembly);
                            }
                            else
                            {
                                ConvertToBox(node, type, ldelem);
                            }
                        }
                    }
                    break;
            }
        }