Merge branch 'develop' into harmony2

This commit is contained in:
ZaneYork 2020-06-05 14:25:18 +08:00
commit 2c4090210f
1 changed files with 32 additions and 36 deletions

View File

@ -1,6 +1,7 @@
using System; using System;
using System.Linq; using System.Linq;
using System.Threading; using System.Threading;
using System.Threading.Tasks;
using Mono.Cecil; using Mono.Cecil;
using Mono.Cecil.Cil; using Mono.Cecil.Cil;
using Mono.Collections.Generic; using Mono.Collections.Generic;
@ -58,47 +59,44 @@ namespace StardewModdingAPI.Framework.ModLoading.Framework
/// <returns>Returns whether the module was modified.</returns> /// <returns>Returns whether the module was modified.</returns>
public bool RewriteModule() public bool RewriteModule()
{ {
// rewrite each type in the assembly, tracking whether any type was rewritten (Item1) int typesChanged = 0;
// and any exception that occurred during rewriting (Item2). Exception exception = null;
var cancellationToken = new CancellationTokenSource();
Tuple<bool, Exception> result = this.Module
.GetTypes()
.Where(type => type.BaseType != null) // skip special types like <Module>
.AsParallel()
.WithExecutionMode(ParallelExecutionMode.ForceParallelism)
.Select(type =>
{
if (cancellationToken.IsCancellationRequested)
return Tuple.Create(false, null as Exception);
bool anyRewritten = false; Parallel.ForEach(
source: this.Module.GetTypes().Where(type => type.BaseType != null), // skip special types like <Module>
body: type =>
{
if (exception != null)
return;
bool changed = false;
try try
{ {
anyRewritten |= this.RewriteCustomAttributes(type.CustomAttributes); changed |= this.RewriteCustomAttributes(type.CustomAttributes);
anyRewritten |= this.RewriteGenericParameters(type.GenericParameters); changed |= this.RewriteGenericParameters(type.GenericParameters);
foreach (InterfaceImplementation @interface in type.Interfaces) foreach (InterfaceImplementation @interface in type.Interfaces)
anyRewritten |= this.RewriteTypeReference(@interface.InterfaceType, newType => @interface.InterfaceType = newType); changed |= this.RewriteTypeReference(@interface.InterfaceType, newType => @interface.InterfaceType = newType);
if (type.BaseType.FullName != "System.Object") if (type.BaseType.FullName != "System.Object")
anyRewritten |= this.RewriteTypeReference(type.BaseType, newType => type.BaseType = newType); changed |= this.RewriteTypeReference(type.BaseType, newType => type.BaseType = newType);
foreach (MethodDefinition method in type.Methods) foreach (MethodDefinition method in type.Methods)
{ {
anyRewritten |= this.RewriteTypeReference(method.ReturnType, newType => method.ReturnType = newType); changed |= this.RewriteTypeReference(method.ReturnType, newType => method.ReturnType = newType);
anyRewritten |= this.RewriteGenericParameters(method.GenericParameters); changed |= this.RewriteGenericParameters(method.GenericParameters);
anyRewritten |= this.RewriteCustomAttributes(method.CustomAttributes); changed |= this.RewriteCustomAttributes(method.CustomAttributes);
foreach (ParameterDefinition parameter in method.Parameters) foreach (ParameterDefinition parameter in method.Parameters)
anyRewritten |= this.RewriteTypeReference(parameter.ParameterType, newType => parameter.ParameterType = newType); changed |= this.RewriteTypeReference(parameter.ParameterType, newType => parameter.ParameterType = newType);
foreach (var methodOverride in method.Overrides) foreach (var methodOverride in method.Overrides)
anyRewritten |= this.RewriteMethodReference(methodOverride); changed |= this.RewriteMethodReference(methodOverride);
if (method.HasBody) if (method.HasBody)
{ {
foreach (VariableDefinition variable in method.Body.Variables) foreach (VariableDefinition variable in method.Body.Variables)
anyRewritten |= this.RewriteTypeReference(variable.VariableType, newType => variable.VariableType = newType); changed |= this.RewriteTypeReference(variable.VariableType, newType => variable.VariableType = newType);
// check CIL instructions // check CIL instructions
ILProcessor cil = method.Body.GetILProcessor(); ILProcessor cil = method.Body.GetILProcessor();
@ -109,31 +107,29 @@ namespace StardewModdingAPI.Framework.ModLoading.Framework
if (instruction.OpCode.Code == Code.Nop) if (instruction.OpCode.Code == Code.Nop)
continue; continue;
anyRewritten |= this.RewriteInstruction(instruction, cil, newInstruction => changed |= this.RewriteInstruction(instruction, cil, newInstruction =>
{ {
anyRewritten = true; changed = true;
cil.Replace(instruction, newInstruction); cil.Replace(instruction, newInstruction);
instruction = newInstruction; instruction = newInstruction;
}); });
} }
} }
} }
return Tuple.Create(anyRewritten, null as Exception);
} }
catch (Exception e) catch (Exception ex)
{ {
cancellationToken.Cancel(); exception ??= ex;
return Tuple.Create(anyRewritten, e);
} }
})
.Aggregate((a, b) => Tuple.Create(a.Item1 || b.Item1, a.Item2 ?? b.Item2));
bool rewritten = result.Item1; if (changed)
Exception exception = result.Item2; Interlocked.Increment(ref typesChanged);
}
);
return exception == null return exception == null
? rewritten ? typesChanged > 0
: throw exception; : throw new Exception($"Rewriting {this.Module.Name} failed.", exception);
} }