Exemple #1
0
 ConstantCallConditional(BasicBlockScanner scanner, MethodDefinition target, int stackDepth, ConstantValue constant)
     : base(scanner)
 {
     Target     = target;
     Constant   = constant;
     StackDepth = stackDepth;
 }
Exemple #2
0
        public static IsWeakInstanceOfConditional Create(BasicBlockScanner scanner, ref BasicBlock bb, ref int index, TypeDefinition type)
        {
            if (bb.Instructions.Count == 1)
            {
                throw new OptimizerAssertionException();
            }
            if (index + 1 >= scanner.Body.Instructions.Count)
            {
                throw new OptimizerAssertionException();
            }

            /*
             * `bool MonoLinkerSupport.IsWeakInstance<T> (object instance)`
             *
             * If the function argument is a simple load (like for instance `Ldarg_0`),
             * then we can simply remove that load.  Otherwise, we need to insert a
             * `Pop` to discard the value on the stack.
             *
             * In either case, we always start a new basic block for the conditional.
             * Its first instruction will either be the simple load or the call itself.
             */

            var argument = scanner.Body.Instructions [index - 1];

            scanner.LogDebug(1, $"WEAK INSTANCE OF: {bb} {index} {type} - {argument}");

            bool           hasLoad;
            TypeDefinition instanceType;

            if (CecilHelper.IsSimpleLoad(argument))
            {
                if (bb.Instructions.Count > 2)
                {
                    scanner.BlockList.SplitBlockAt(ref bb, bb.Instructions.Count - 2);
                }
                instanceType = CecilHelper.GetWeakInstanceArgument(bb.Instructions [1]);
                hasLoad      = true;
            }
            else
            {
                scanner.BlockList.SplitBlockAt(ref bb, bb.Instructions.Count - 1);
                instanceType = CecilHelper.GetWeakInstanceArgument(bb.Instructions [0]);
                hasLoad      = false;
            }

            var instance = new IsWeakInstanceOfConditional(scanner, instanceType, hasLoad);

            bb.LinkerConditional = instance;

            /*
             * Once we get here, the current block only contains the (optional) simple load
             * and the conditional call itself.
             */

            LookAheadAfterConditional(scanner.BlockList, ref bb, ref index);

            return(instance);
        }
Exemple #3
0
        public static ConstantCallConditional Create(BasicBlockScanner scanner, ref BasicBlock bb, ref int index, MethodDefinition target, ConstantValue constant)
        {
            if (index + 1 >= scanner.Body.Instructions.Count)
            {
                throw new OptimizerAssertionException();
            }

            /*
             * Calling a constant property.
             *
             */

            int stackDepth;
            int size = 1;

            if (target.IsStatic)
            {
                stackDepth = 0;
            }
            else if (bb.Count == 1)
            {
                stackDepth = 1;
            }
            else
            {
                var previous = scanner.Body.Instructions [index - 1];
                if (CecilHelper.IsSimpleLoad(previous) || previous.OpCode.Code == Code.Nop)
                {
                    stackDepth = 0;
                    size++;
                }
                else
                {
                    stackDepth = 1;
                }
            }

            if (bb.Instructions.Count > size)
            {
                scanner.BlockList.SplitBlockAt(ref bb, bb.Instructions.Count - size);
            }

            var instance = new ConstantCallConditional(scanner, target, stackDepth, constant);

            bb.LinkerConditional = instance;

            LookAheadAfterConditional(scanner.BlockList, ref bb, ref index);

            return(instance);
        }
        public static AsWeakInstanceOfConditional Create(BasicBlockScanner scanner, ref BasicBlock bb, ref int index, TypeDefinition type)
        {
            if (bb.Instructions.Count < 2)
            {
                throw new OptimizerAssertionException();
            }
            if (index + 1 >= scanner.Body.Instructions.Count)
            {
                throw new OptimizerAssertionException();
            }

            /*
             * `bool MonoLinkerSupport.AsWeakInstance<T> (object obj, out T instance)`
             */

            var load   = scanner.Body.Instructions [index - 2];
            var output = scanner.Body.Instructions [index - 1];

            scanner.LogDebug(1, $"WEAK INSTANCE OF: {bb} {index} {type} - {load} {output}");

            if (!CecilHelper.IsSimpleLoad(load))
            {
                throw new OptimizerAssertionException();
            }
            if (output.OpCode.Code != Code.Ldloca && output.OpCode.Code != Code.Ldloca_S)
            {
                throw new OptimizerAssertionException();
            }

            if (bb.Instructions.Count > 3)
            {
                scanner.BlockList.SplitBlockAt(ref bb, bb.Instructions.Count - 2);
            }
            var instanceType = CecilHelper.GetWeakInstanceArgument(bb.Instructions [2]);
            var variable     = ((VariableReference)output.Operand).Resolve() ?? throw new OptimizerAssertionException();

            var instance = new AsWeakInstanceOfConditional(scanner, instanceType, variable);

            bb.LinkerConditional = instance;

            /*
             * Once we get here, the current block only contains the (optional) simple load
             * and the conditional call itself.
             */

            LookAheadAfterConditional(scanner.BlockList, ref bb, ref index);

            return(instance);
        }
        protected override void MarkMethodBody(MethodBody body)
        {
            if (!OptimizerContext.IsEnabled(body.Method))
            {
                base.MarkMethodBody(body);
                return;
            }

            var debug = OptimizerContext.GetDebugLevel(body.Method);

            if (debug > 0)
            {
                OptimizerContext.LogMessage(MessageImportance.Normal, $"MARK BODY: {body.Method}");
                OptimizerContext.Debug();
            }

            var scanner = BasicBlockScanner.Scan(OptimizerContext, body.Method);

            if (scanner == null)
            {
                OptimizerContext.LogDebug($"BB SCAN FAILED: {body.Method}");
                base.MarkMethodBody(body);
                return;
            }

            if (scanner == null || !scanner.FoundConditionals)
            {
                base.MarkMethodBody(body);
                return;
            }

            if (debug > 0)
            {
                OptimizerContext.LogDebug($"MARK BODY - CONDITIONAL: {body.Method}");
            }

            scanner.RewriteConditionals();

            base.MarkMethodBody(body);
        }
        void ProcessProperty(PropertyDefinition property)
        {
            if (property.SetMethod != null)
            {
                return;
            }
            if (property.GetMethod == null || !property.GetMethod.HasBody)
            {
                return;
            }
            if (property.PropertyType.MetadataType != MetadataType.Boolean)
            {
                return;
            }

            var scanner = BasicBlockScanner.Scan(Context, property.GetMethod);

            if (scanner == null || !scanner.FoundConditionals)
            {
                return;
            }

            Context.LogMessage(MessageImportance.Normal, $"Found conditional property: {property}");

            scanner.RewriteConditionals();

            if (!CecilHelper.IsConstantLoad(scanner.Body, out var value))
            {
                Context.LogMessage(MessageImportance.High, $"Property `{property}` uses conditionals, but does not return a constant.");
                return;
            }

            Context.MarkAsConstantMethod(property.GetMethod, value ? ConstantValue.True : ConstantValue.False);

            Context.Debug();
        }
Exemple #7
0
 IsWeakInstanceOfConditional(BasicBlockScanner scanner, TypeDefinition type, bool hasLoad)
     : base(scanner)
 {
     InstanceType       = type;
     HasLoadInstruction = hasLoad;
 }
Exemple #8
0
 protected LinkerConditional(BasicBlockScanner scanner)
 {
     Scanner = scanner;
 }
Exemple #9
0
        public static bool Scan(BasicBlockScanner scanner, ref BasicBlock bb, ref int index, Instruction instruction)
        {
            var reference = (MethodReference)instruction.Operand;

            if (!scanner.Context.TryFastResolve(reference, out var target))
            {
                return(false);
            }

            if (target == null)
            {
                if (reference.DeclaringType.Name.Contains("..."))
                {
                    // FIXME: we don't support Ranges yet.
                    return(false);
                }
                scanner.Context.LogMessage(MessageImportance.High, $"Cannot resolve call target: {CecilHelper.Format (instruction)}");
                if (scanner.Context.Options.IgnoreResolutionErrors)
                {
                    return(false);
                }
                throw new ResolutionException(reference);
            }
            scanner.LogDebug(2, $"    CALL: {target}");

            if (instruction.Operand is GenericInstanceMethod genericInstance)
            {
                if (scanner.Context.IsWeakInstanceOfMethod(target))
                {
                    var conditionalType = genericInstance.GenericArguments [0].Resolve();
                    if (conditionalType == null)
                    {
                        throw new ResolutionException(genericInstance.GenericArguments [0]);
                    }
                    IsWeakInstanceOfConditional.Create(scanner, ref bb, ref index, conditionalType);
                    return(true);
                }
                else if (scanner.Context.AsWeakInstanceOfMethod(target))
                {
                    var conditionalType = genericInstance.GenericArguments [0].Resolve();
                    if (conditionalType == null)
                    {
                        throw new ResolutionException(genericInstance.GenericArguments [0]);
                    }
                    AsWeakInstanceOfConditional.Create(scanner, ref bb, ref index, conditionalType);
                    return(true);
                }
                else if (scanner.Context.IsTypeAvailableMethod(target))
                {
                    var conditionalType = genericInstance.GenericArguments [0].Resolve();
                    if (conditionalType == null)
                    {
                        throw new ResolutionException(genericInstance.GenericArguments [0]);
                    }
                    IsTypeAvailableConditional.Create(scanner, ref bb, ref index, conditionalType);
                    return(true);
                }
                return(false);
            }

            if (scanner.Context.IsFeatureSupportedMethod(target))
            {
                IsFeatureSupportedConditional.Create(scanner, ref bb, ref index);
                return(true);
            }

            if (scanner.Context.IsTypeNameAvailableMethod(target))
            {
                IsTypeAvailableConditional.Create(scanner, ref bb, ref index);
                return(true);
            }


            if (scanner.Context.IsRequireFeatureMethod(target))
            {
                RequireFeatureConditional.Create(scanner, ref bb, ref index);
                return(true);
            }

            if (scanner.Context.TryGetConstantMethod(target, out var constant))
            {
                ConstantCallConditional.Create(scanner, ref bb, ref index, target, constant);
                return(true);
            }

            return(false);
        }
Exemple #10
0
 IsTypeAvailableConditional(BasicBlockScanner scanner, string name)
     : base(scanner)
 {
     ConditionalTypeName = name;
 }
Exemple #11
0
 IsTypeAvailableConditional(BasicBlockScanner scanner, TypeDefinition type)
     : base(scanner)
 {
     ConditionalType = type;
 }
Exemple #12
0
 RequireFeatureConditional(BasicBlockScanner scanner, MonoLinkerFeature feature)
     : base(scanner)
 {
     Feature = feature;
 }
 IsFeatureSupportedConditional(BasicBlockScanner scanner, MonoLinkerFeature feature)
     : base(scanner)
 {
     Feature = feature;
 }
 AsWeakInstanceOfConditional(BasicBlockScanner scanner, TypeDefinition type, VariableDefinition variable)
     : base(scanner)
 {
     InstanceType = type;
     Variable     = variable;
 }