using Mono.Cecil;
using Mono.Cecil.Cil;
using XFESystem.Collections;
namespace XFESystem.Tools.JintCleanupPatch;
public static partial class Program
{
private const string RegexLiteralMarker = "XFESystem.JintLiteralRegexReplacementV1";
private static bool OriginalLiteralCall(Instruction instruction) => instruction.Operand is MethodReference call &&
call.DeclaringType.FullName == "System.Text.RegularExpressions.Regex" && call.Name == "Replace" &&
call.Parameters.Count == 3 && call.Parameters[0].ParameterType.FullName == "System.String" &&
call.Parameters[1].ParameterType.FullName == "System.String" && call.Parameters[2].ParameterType.FullName == "System.Int32";
private static bool PatchedLiteralCall(Instruction instruction) => instruction.Operand is MethodReference call &&
call.DeclaringType.FullName == typeof(LiteralRegexReplacement).FullName && call.Name == "Replace";
private static void PatchRegexLiteral(ModuleDefinition module)
{
if (module.GetType(RegexLiteralMarker) is not null) { ValidateRegexLiteral(module); return; }
var replace = module.GetType("Jint.Native.RegExp.RegExpPrototype").Methods.Single(method => method.Name == "Replace");
var calls = replace.Body.Instructions.Where(OriginalLiteralCall).ToArray();
if (calls.Length != 1 || replace.Body.Instructions.Any(PatchedLiteralCall))
throw new InvalidOperationException("Pinned literal regex replacement call shape changed.");
calls[0].OpCode = OpCodes.Call;
calls[0].Operand = module.ImportReference(typeof(LiteralRegexReplacement).GetMethod(nameof(LiteralRegexReplacement.Replace))!);
module.Types.Add(new("XFESystem", "JintLiteralRegexReplacementV1", TypeAttributes.NotPublic | TypeAttributes.Abstract | TypeAttributes.Sealed, module.TypeSystem.Object));
ValidateRegexLiteral(module);
}
private static void ValidateRegexLiteral(ModuleDefinition module)
{
var replace = module.GetType("Jint.Native.RegExp.RegExpPrototype").Methods.Single(method => method.Name == "Replace");
if (module.GetType(RegexLiteralMarker) is null || replace.Body.Instructions.Any(OriginalLiteralCall) ||
replace.Body.Instructions.Count(PatchedLiteralCall) != 1 ||
replace.Body.Instructions.Single(PatchedLiteralCall).OpCode != OpCodes.Call)
throw new InvalidOperationException("The literal regex replacement 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 RegexLiteralMarker = "XFESystem.JintLiteralRegexReplacementV1";
private static bool OriginalLiteralCall(Instruction instruction) => instruction.Operand is MethodReference call &&
call.DeclaringType.FullName == "System.Text.RegularExpressions.Regex" && call.Name == "Replace" &&
call.Parameters.Count == 3 && call.Parameters[0].ParameterType.FullName == "System.String" &&
call.Parameters[1].ParameterType.FullName == "System.String" && call.Parameters[2].ParameterType.FullName == "System.Int32";
private static bool PatchedLiteralCall(Instruction instruction) => instruction.Operand is MethodReference call &&
call.DeclaringType.FullName == typeof(LiteralRegexReplacement).FullName && call.Name == "Replace";
private static void PatchRegexLiteral(ModuleDefinition module)
{
if (module.GetType(RegexLiteralMarker) is not null) { ValidateRegexLiteral(module); return; }
var replace = module.GetType("Jint.Native.RegExp.RegExpPrototype").Methods.Single(method => method.Name == "Replace");
var calls = replace.Body.Instructions.Where(OriginalLiteralCall).ToArray();
if (calls.Length != 1 || replace.Body.Instructions.Any(PatchedLiteralCall))
throw new InvalidOperationException("Pinned literal regex replacement call shape changed.");
calls[0].OpCode = OpCodes.Call;
calls[0].Operand = module.ImportReference(typeof(LiteralRegexReplacement).GetMethod(nameof(LiteralRegexReplacement.Replace))!);
module.Types.Add(new("XFESystem", "JintLiteralRegexReplacementV1", TypeAttributes.NotPublic | TypeAttributes.Abstract | TypeAttributes.Sealed, module.TypeSystem.Object));
ValidateRegexLiteral(module);
}
private static void ValidateRegexLiteral(ModuleDefinition module)
{
var replace = module.GetType("Jint.Native.RegExp.RegExpPrototype").Methods.Single(method => method.Name == "Replace");
if (module.GetType(RegexLiteralMarker) is null || replace.Body.Instructions.Any(OriginalLiteralCall) ||
replace.Body.Instructions.Count(PatchedLiteralCall) != 1 ||
replace.Body.Instructions.Single(PatchedLiteralCall).OpCode != OpCodes.Call)
throw new InvalidOperationException("The literal regex replacement patch is incomplete.");
}
}