simplify & optimise instruction searching a bit (#247)

This commit is contained in:
Jesse Plamondon-Willard 2017-03-12 17:51:59 -04:00
parent a12bcf3b78
commit a6ed67a9f7
1 changed files with 12 additions and 29 deletions

View File

@ -191,46 +191,29 @@ namespace StardewModdingAPI.Framework
this.ChangeTypeScope(type);
}
// throw exception if assembly contains incompatible instructions can't be rewritten
{
IInstructionFinder[] finders = Constants.GetIncompatibilityFinders().ToArray();
foreach (MethodDefinition method in this.GetMethods(module))
{
foreach (Instruction instruction in method.Body.Instructions)
{
foreach (IInstructionFinder finder in finders)
{
if (finder.IsMatch(instruction, platformChanged))
throw new IncompatibleInstructionException(finder.NounPhrase, $"Found an incompatible CIL instruction ({finder.NounPhrase}) while loading assembly {assembly.Name.Name}.");
}
}
}
}
// rewrite incompatible instructions
// find incompatible instructions
bool anyRewritten = false;
IInstructionFinder[] finders = Constants.GetIncompatibilityFinders().ToArray();
IInstructionRewriter[] rewriters = Constants.GetRewriters().ToArray();
foreach (MethodDefinition method in this.GetMethods(module))
{
// skip methods with no rewritable instructions
bool canRewrite = method.Body.Instructions.Any(op => rewriters.Any(rewriter => rewriter.IsMatch(op, platformChanged)));
if (!canRewrite)
continue;
// rewrite instructions
ILProcessor cil = method.Body.GetILProcessor();
foreach (Instruction op in cil.Body.Instructions.ToArray())
foreach (Instruction instruction in cil.Body.Instructions.ToArray())
{
IInstructionRewriter rewriter = rewriters.FirstOrDefault(p => p.IsMatch(op, platformChanged));
// throw exception if instruction is incompatible but can't be rewritten
IInstructionFinder finder = finders.FirstOrDefault(p => p.IsMatch(instruction, platformChanged));
if (finder != null)
throw new IncompatibleInstructionException(finder.NounPhrase, $"Found an incompatible CIL instruction ({finder.NounPhrase}) while loading assembly {assembly.Name.Name}.");
// rewrite instruction if needed
IInstructionRewriter rewriter = rewriters.FirstOrDefault(p => p.IsMatch(instruction, platformChanged));
if (rewriter != null)
{
this.LogOnce(this.Monitor, loggedRewrites, $"Rewriting {assembly.Name.Name} to fix {rewriter.NounPhrase}...");
rewriter.Rewrite(module, cil, op, this.AssemblyMap);
rewriter.Rewrite(module, cil, instruction, this.AssemblyMap);
anyRewritten = true;
}
}
// finalise method
anyRewritten = true;
}
return platformChanged || anyRewritten;