using System.Diagnostics;
using System.Reflection;
using Jint;
using Jint.Native;
using Jint.Runtime.Interop;
using XFESystem.Browser;
// Host-only diagnostic. Calls the original intrinsic directly, under the
// existing evaluation budget; never replaces regex results or resets limits.
internal sealed class MonacoRegexProfile
{
private sealed class Work
{
public long Calls, Ticks, InputCharacters, FailedSuffixHits;
}
private readonly Dictionary<string, Work> patterns = new(StringComparer.Ordinal);
internal void Install(BrowserService browser)
{
var runtime = (JavaScriptRuntime)typeof(BrowserService).GetField("runtime", BindingFlags.Instance | BindingFlags.NonPublic)!.GetValue(browser)!;
var engine = (Engine)typeof(JavaScriptRuntime).GetField("engine", BindingFlags.Instance | BindingFlags.NonPublic)!.GetValue(runtime)!;
var prototype = engine.GetValue("RegExp").AsObject().Get("prototype").AsObject();
var original = (Func<JsValue, JsValue[], JsValue>)prototype.Get("exec").ToObject()!;
var hitCounter = typeof(Jint.Native.JsRegExp).GetField("_xfeNoMatchHits", BindingFlags.Instance | BindingFlags.NonPublic);
prototype.Set("exec", new ClrFunction(engine, "exec", (receiver, arguments) =>
{
var regex = receiver.AsObject();
string key = regex.Get("source").AsString() + "/" + regex.Get("flags").AsString();
if (!patterns.TryGetValue(key, out var work)) patterns.Add(key, work = new());
work.Calls++;
if (arguments.Length > 0 && arguments[0].IsString()) work.InputCharacters += arguments[0].AsString().Length;
long started = Stopwatch.GetTimestamp();
long beforeHits = (long?)hitCounter?.GetValue(regex) ?? 0;
var result = original(receiver, arguments);
work.Ticks += Stopwatch.GetTimestamp() - started;
work.FailedSuffixHits += ((long?)hitCounter?.GetValue(regex) ?? 0) - beforeHits;
return result;
}), false);
}
internal object[] Results() => patterns.OrderByDescending(pair => pair.Value.Ticks).Take(20).Select(pair => (object)new
{
Pattern = pair.Key, pair.Value.Calls, pair.Value.InputCharacters, pair.Value.FailedSuffixHits,
Milliseconds = pair.Value.Ticks * 1000.0 / Stopwatch.Frequency
}).ToArray();
}
using System.Diagnostics;
using System.Reflection;
using Jint;
using Jint.Native;
using Jint.Runtime.Interop;
using XFESystem.Browser;
// Host-only diagnostic. Calls the original intrinsic directly, under the
// existing evaluation budget; never replaces regex results or resets limits.
internal sealed class MonacoRegexProfile
{
private sealed class Work
{
public long Calls, Ticks, InputCharacters, FailedSuffixHits;
}
private readonly Dictionary<string, Work> patterns = new(StringComparer.Ordinal);
internal void Install(BrowserService browser)
{
var runtime = (JavaScriptRuntime)typeof(BrowserService).GetField("runtime", BindingFlags.Instance | BindingFlags.NonPublic)!.GetValue(browser)!;
var engine = (Engine)typeof(JavaScriptRuntime).GetField("engine", BindingFlags.Instance | BindingFlags.NonPublic)!.GetValue(runtime)!;
var prototype = engine.GetValue("RegExp").AsObject().Get("prototype").AsObject();
var original = (Func<JsValue, JsValue[], JsValue>)prototype.Get("exec").ToObject()!;
var hitCounter = typeof(Jint.Native.JsRegExp).GetField("_xfeNoMatchHits", BindingFlags.Instance | BindingFlags.NonPublic);
prototype.Set("exec", new ClrFunction(engine, "exec", (receiver, arguments) =>
{
var regex = receiver.AsObject();
string key = regex.Get("source").AsString() + "/" + regex.Get("flags").AsString();
if (!patterns.TryGetValue(key, out var work)) patterns.Add(key, work = new());
work.Calls++;
if (arguments.Length > 0 && arguments[0].IsString()) work.InputCharacters += arguments[0].AsString().Length;
long started = Stopwatch.GetTimestamp();
long beforeHits = (long?)hitCounter?.GetValue(regex) ?? 0;
var result = original(receiver, arguments);
work.Ticks += Stopwatch.GetTimestamp() - started;
work.FailedSuffixHits += ((long?)hitCounter?.GetValue(regex) ?? 0) - beforeHits;
return result;
}), false);
}
internal object[] Results() => patterns.OrderByDescending(pair => pair.Value.Ticks).Take(20).Select(pair => (object)new
{
Pattern = pair.Key, pair.Value.Calls, pair.Value.InputCharacters, pair.Value.FailedSuffixHits,
Milliseconds = pair.Value.Ticks * 1000.0 / Stopwatch.Frequency
}).ToArray();
}