using Mono.Cecil;
using Mono.Cecil.Cil;
using XFESystem.Collections;
namespace XFESystem.Tools.JintCleanupPatch;
public static partial class Program
{
private const string RegexSchedulingMarker = "XFESystem.JintRegexSchedulingV1";
private static void PatchRegexScheduling(ModuleDefinition module)
{
if (module.GetType(RegexSchedulingMarker) is not null) { ValidateRegexScheduling(module); return; }
var type = module.GetType("Jint.Native.RegExp.RegExpPrototype"); int count = 0;
foreach (var method in type.Methods.Where(method => method.HasBody))
foreach (var instruction in method.Body.Instructions)
if (instruction.Operand is MethodReference call && call.DeclaringType.FullName == "System.Text.RegularExpressions.Regex" && call.Name is "Match" or "IsMatch")
{
var parameterTypes = new[] { typeof(System.Text.RegularExpressions.Regex) }.Concat(call.Parameters.Select(p => p.ParameterType.FullName switch
{ "System.String" => typeof(string), "System.Int32" => typeof(int), _ => throw new InvalidOperationException("Pinned regex match overload changed.") })).ToArray();
var replacement = typeof(RegexPauseRecovery).GetMethod(call.Name, parameterTypes) ?? throw new InvalidOperationException("Pinned regex match recovery overload is missing.");
instruction.OpCode = OpCodes.Call; instruction.Operand = module.ImportReference(replacement); count++;
}
if (count != 6) throw new InvalidOperationException("Pinned regex match scheduling call count changed: " + count);
module.Types.Add(new("XFESystem", "JintRegexSchedulingV1", TypeAttributes.NotPublic | TypeAttributes.Abstract | TypeAttributes.Sealed, module.TypeSystem.Object));
ValidateRegexScheduling(module);
}
private static void ValidateRegexScheduling(ModuleDefinition module)
{
var calls = module.GetType("Jint.Native.RegExp.RegExpPrototype").Methods.Where(m => m.HasBody).SelectMany(m => m.Body.Instructions).ToArray();
if (module.GetType(RegexSchedulingMarker) is null || calls.Count(i => i.OpCode == OpCodes.Call && i.Operand is MethodReference call && call.DeclaringType.FullName == typeof(RegexPauseRecovery).FullName) != 6 ||
calls.Any(i => i.Operand is MethodReference call && call.DeclaringType.FullName == "System.Text.RegularExpressions.Regex" && call.Name is "Match" or "IsMatch"))
throw new InvalidOperationException("The regex scheduling patch is incomplete.");
}
}
using Mono.Cecil;
using Mono.Cecil.Cil;
using XFESystem.Collections;
namespace XFESystem.Tools.JintCleanupPatch;
public static partial class Program
{
private const string RegexSchedulingMarker = "XFESystem.JintRegexSchedulingV1";
private static void PatchRegexScheduling(ModuleDefinition module)
{
if (module.GetType(RegexSchedulingMarker) is not null) { ValidateRegexScheduling(module); return; }
var type = module.GetType("Jint.Native.RegExp.RegExpPrototype"); int count = 0;
foreach (var method in type.Methods.Where(method => method.HasBody))
foreach (var instruction in method.Body.Instructions)
if (instruction.Operand is MethodReference call && call.DeclaringType.FullName == "System.Text.RegularExpressions.Regex" && call.Name is "Match" or "IsMatch")
{
var parameterTypes = new[] { typeof(System.Text.RegularExpressions.Regex) }.Concat(call.Parameters.Select(p => p.ParameterType.FullName switch
{ "System.String" => typeof(string), "System.Int32" => typeof(int), _ => throw new InvalidOperationException("Pinned regex match overload changed.") })).ToArray();
var replacement = typeof(RegexPauseRecovery).GetMethod(call.Name, parameterTypes) ?? throw new InvalidOperationException("Pinned regex match recovery overload is missing.");
instruction.OpCode = OpCodes.Call; instruction.Operand = module.ImportReference(replacement); count++;
}
if (count != 6) throw new InvalidOperationException("Pinned regex match scheduling call count changed: " + count);
module.Types.Add(new("XFESystem", "JintRegexSchedulingV1", TypeAttributes.NotPublic | TypeAttributes.Abstract | TypeAttributes.Sealed, module.TypeSystem.Object));
ValidateRegexScheduling(module);
}
private static void ValidateRegexScheduling(ModuleDefinition module)
{
var calls = module.GetType("Jint.Native.RegExp.RegExpPrototype").Methods.Where(m => m.HasBody).SelectMany(m => m.Body.Instructions).ToArray();
if (module.GetType(RegexSchedulingMarker) is null || calls.Count(i => i.OpCode == OpCodes.Call && i.Operand is MethodReference call && call.DeclaringType.FullName == typeof(RegexPauseRecovery).FullName) != 6 ||
calls.Any(i => i.Operand is MethodReference call && call.DeclaringType.FullName == "System.Text.RegularExpressions.Regex" && call.Name is "Match" or "IsMatch"))
throw new InvalidOperationException("The regex scheduling patch is incomplete.");
}
}