ConstantCallConditional(BasicBlockScanner scanner, MethodDefinition target, int stackDepth, ConstantValue constant) : base(scanner) { Target = target; Constant = constant; StackDepth = stackDepth; }
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); }
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(); }
IsWeakInstanceOfConditional(BasicBlockScanner scanner, TypeDefinition type, bool hasLoad) : base(scanner) { InstanceType = type; HasLoadInstruction = hasLoad; }
protected LinkerConditional(BasicBlockScanner scanner) { Scanner = scanner; }
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); }
IsTypeAvailableConditional(BasicBlockScanner scanner, string name) : base(scanner) { ConditionalTypeName = name; }
IsTypeAvailableConditional(BasicBlockScanner scanner, TypeDefinition type) : base(scanner) { ConditionalType = type; }
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; }