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 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); }
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); }