From 6f4063cd868539a3de2057a363681c48da029f4e Mon Sep 17 00:00:00 2001 From: Jesse Plamondon-Willard Date: Tue, 2 Jun 2020 17:52:54 -0400 Subject: [PATCH 1/3] add release note (#716) --- docs/release-notes.md | 1 + 1 file changed, 1 insertion(+) diff --git a/docs/release-notes.md b/docs/release-notes.md index dcb4a485..b2ef5a8d 100644 --- a/docs/release-notes.md +++ b/docs/release-notes.md @@ -6,6 +6,7 @@ * Mod warnings are now listed alphabetically. * MacOS files starting with `._` are now ignored and can no longer cause skipped mods. * Simplified paranoid warning logs and reduced their log level. + * Reduced startup time when loading mod DLLs (thanks to ZaneYork!). * Fixed `BadImageFormatException` error detection. * Fixed black maps on Android for mods which use `.tmx` files. From 73e3735dcd3b5789d4541e22988db9db2854a69f Mon Sep 17 00:00:00 2001 From: Jesse Plamondon-Willard Date: Tue, 2 Jun 2020 22:05:00 -0400 Subject: [PATCH 2/3] undo parallel loop (#716) This caused errors during rewriting to be obfuscated with null reference exceptions. --- docs/release-notes.md | 1 - .../ModLoading/Framework/RecursiveRewriter.cs | 11 ++++++----- 2 files changed, 6 insertions(+), 6 deletions(-) diff --git a/docs/release-notes.md b/docs/release-notes.md index b2ef5a8d..dcb4a485 100644 --- a/docs/release-notes.md +++ b/docs/release-notes.md @@ -6,7 +6,6 @@ * Mod warnings are now listed alphabetically. * MacOS files starting with `._` are now ignored and can no longer cause skipped mods. * Simplified paranoid warning logs and reduced their log level. - * Reduced startup time when loading mod DLLs (thanks to ZaneYork!). * Fixed `BadImageFormatException` error detection. * Fixed black maps on Android for mods which use `.tmx` files. diff --git a/src/SMAPI/Framework/ModLoading/Framework/RecursiveRewriter.cs b/src/SMAPI/Framework/ModLoading/Framework/RecursiveRewriter.cs index aafdefc6..c774c038 100644 --- a/src/SMAPI/Framework/ModLoading/Framework/RecursiveRewriter.cs +++ b/src/SMAPI/Framework/ModLoading/Framework/RecursiveRewriter.cs @@ -57,11 +57,12 @@ namespace StardewModdingAPI.Framework.ModLoading.Framework /// Returns whether the module was modified. public bool RewriteModule() { - return this.Module.GetTypes().AsParallel().WithExecutionMode(ParallelExecutionMode.ForceParallelism).Select(type => + bool anyRewritten = false; + + foreach (TypeDefinition type in this.Module.GetTypes()) { - bool anyRewritten = false; if (type.BaseType == null) - return false; // special type like + continue; // special type like anyRewritten |= this.RewriteCustomAttributes(type.CustomAttributes); anyRewritten |= this.RewriteGenericParameters(type.GenericParameters); @@ -107,9 +108,9 @@ namespace StardewModdingAPI.Framework.ModLoading.Framework } } } + } - return anyRewritten; - }).Max(); + return anyRewritten; } From 6b4e52febbd69cc6b25735c96d89910d41e09d93 Mon Sep 17 00:00:00 2001 From: ZaneYork Date: Wed, 3 Jun 2020 10:56:31 +0800 Subject: [PATCH 3/3] Parallel exception aggregate fix --- .../ModLoading/Framework/RecursiveRewriter.cs | 109 ++++++++++-------- 1 file changed, 62 insertions(+), 47 deletions(-) diff --git a/src/SMAPI/Framework/ModLoading/Framework/RecursiveRewriter.cs b/src/SMAPI/Framework/ModLoading/Framework/RecursiveRewriter.cs index c774c038..c03376d6 100644 --- a/src/SMAPI/Framework/ModLoading/Framework/RecursiveRewriter.cs +++ b/src/SMAPI/Framework/ModLoading/Framework/RecursiveRewriter.cs @@ -57,60 +57,75 @@ namespace StardewModdingAPI.Framework.ModLoading.Framework /// Returns whether the module was modified. public bool RewriteModule() { - bool anyRewritten = false; - - foreach (TypeDefinition type in this.Module.GetTypes()) - { - if (type.BaseType == null) - continue; // special type like - - anyRewritten |= this.RewriteCustomAttributes(type.CustomAttributes); - anyRewritten |= this.RewriteGenericParameters(type.GenericParameters); - - foreach (InterfaceImplementation @interface in type.Interfaces) - anyRewritten |= this.RewriteTypeReference(@interface.InterfaceType, newType => @interface.InterfaceType = newType); - - if (type.BaseType.FullName != "System.Object") - anyRewritten |= this.RewriteTypeReference(type.BaseType, newType => type.BaseType = newType); - - foreach (MethodDefinition method in type.Methods) + Tuple aggregateResult = this.Module.GetTypes() + .AsParallel().WithExecutionMode(ParallelExecutionMode.ForceParallelism) + .Select(type => { - anyRewritten |= this.RewriteTypeReference(method.ReturnType, newType => method.ReturnType = newType); - anyRewritten |= this.RewriteGenericParameters(method.GenericParameters); - anyRewritten |= this.RewriteCustomAttributes(method.CustomAttributes); - - foreach (ParameterDefinition parameter in method.Parameters) - anyRewritten |= this.RewriteTypeReference(parameter.ParameterType, newType => parameter.ParameterType = newType); - - foreach (var methodOverride in method.Overrides) - anyRewritten |= this.RewriteMethodReference(methodOverride); - - if (method.HasBody) + try { - foreach (VariableDefinition variable in method.Body.Variables) - anyRewritten |= this.RewriteTypeReference(variable.VariableType, newType => variable.VariableType = newType); + bool anyRewritten = false; + if (type.BaseType == null) + return new Tuple(anyRewritten, null); // special type like - // check CIL instructions - ILProcessor cil = method.Body.GetILProcessor(); - Collection instructions = cil.Body.Instructions; - for (int i = 0; i < instructions.Count; i++) + anyRewritten |= this.RewriteCustomAttributes(type.CustomAttributes); + anyRewritten |= this.RewriteGenericParameters(type.GenericParameters); + + foreach (InterfaceImplementation @interface in type.Interfaces) + anyRewritten |= this.RewriteTypeReference(@interface.InterfaceType, newType => @interface.InterfaceType = newType); + + if (type.BaseType.FullName != "System.Object") + anyRewritten |= this.RewriteTypeReference(type.BaseType, newType => type.BaseType = newType); + + foreach (MethodDefinition method in type.Methods) { - var instruction = instructions[i]; - if (instruction.OpCode.Code == Code.Nop) - continue; + anyRewritten |= this.RewriteTypeReference(method.ReturnType, newType => method.ReturnType = newType); + anyRewritten |= this.RewriteGenericParameters(method.GenericParameters); + anyRewritten |= this.RewriteCustomAttributes(method.CustomAttributes); - anyRewritten |= this.RewriteInstruction(instruction, cil, newInstruction => + foreach (ParameterDefinition parameter in method.Parameters) + anyRewritten |= this.RewriteTypeReference(parameter.ParameterType, newType => parameter.ParameterType = newType); + + foreach (var methodOverride in method.Overrides) + anyRewritten |= this.RewriteMethodReference(methodOverride); + + if (method.HasBody) { - anyRewritten = true; - cil.Replace(instruction, newInstruction); - instruction = newInstruction; - }); - } - } - } - } + foreach (VariableDefinition variable in method.Body.Variables) + anyRewritten |= this.RewriteTypeReference(variable.VariableType, newType => variable.VariableType = newType); - return anyRewritten; + // check CIL instructions + ILProcessor cil = method.Body.GetILProcessor(); + Collection instructions = cil.Body.Instructions; + for (int i = 0; i < instructions.Count; i++) + { + var instruction = instructions[i]; + if (instruction.OpCode.Code == Code.Nop) + continue; + + anyRewritten |= this.RewriteInstruction(instruction, cil, newInstruction => + { + anyRewritten = true; + cil.Replace(instruction, newInstruction); + instruction = newInstruction; + }); + } + } + } + + return new Tuple(anyRewritten, null); + } + catch (Exception e) + { + return new Tuple(false, e.InnerException ?? e); + } + }) + .TakeWhile(tuple => tuple.Item2 == null) // Stop on any exception occurs + .Aggregate((tupleA, tupleB) => new Tuple(tupleA.Item1 | tupleB.Item1, tupleA.Item2 ?? tupleB.Item2)); // Aggregate result and exception + if (aggregateResult.Item2 != null) + { + throw aggregateResult.Item2; // rethrow inner Exception + } + return aggregateResult.Item1; }