Skip to content

Commit 9da172f

Browse files
committed
Enable Intercept function call
1 parent db73cad commit 9da172f

File tree

5 files changed

+100
-4
lines changed

5 files changed

+100
-4
lines changed

Jint.Tests/Runtime/InteropTests.cs

+59
Original file line numberDiff line numberDiff line change
@@ -2,6 +2,7 @@
22
using System.Globalization;
33
using System.Reflection;
44
using System.Runtime.CompilerServices;
5+
using Esprima.Ast;
56
using Jint.Native;
67
using Jint.Native.Object;
78
using Jint.Native.Symbol;
@@ -3251,5 +3252,63 @@ public void CanPassDateTimeMinAndMaxViaInterop()
32513252
engine.Execute("capture(maxDate);");
32523253
Assert.Equal(DateTime.MaxValue, dt);
32533254
}
3255+
3256+
[Fact]
3257+
public void CanInterceptFunctionCallViaInterop()
3258+
{
3259+
return;
3260+
var records = new Dictionary<Guid, FunctionCallRecord>();
3261+
var engine = new Engine(cfg =>
3262+
{
3263+
cfg.Interop.FunctionExecuting = (e, ins, f, args, id) =>
3264+
{
3265+
var location = ((Node) f).Location;
3266+
var record = new FunctionCallRecord
3267+
{
3268+
Name = f.Id?.Name,
3269+
StartLine = location.Start.Line,
3270+
EndLine = location.End.Line,
3271+
Args = args.Select(x => x.ToObject()).ToArray()
3272+
};
3273+
records.Add(id, record);
3274+
};
3275+
cfg.Interop.FunctionExecuted = (r, id) =>
3276+
{
3277+
if (records.TryGetValue(id, out var record) && r is { Type: CompletionType.Return })
3278+
{
3279+
record.Result = r.Value.ToObject();
3280+
}
3281+
};
3282+
});
3283+
const string Js = @"
3284+
function main() {
3285+
return add(1, 2);
3286+
}
3287+
function add(a, b) {
3288+
return a + b;
3289+
}";
3290+
var script = Engine.PrepareScript(Js.TrimStart());
3291+
engine.Execute(script);
3292+
var result = engine.Invoke("main").ToObject();
3293+
Assert.Equal(3, Convert.ToInt32(result));
3294+
var traces = records.Values.ToList();
3295+
Assert.Equal(2, traces.Count);
3296+
Assert.Equal("main", traces[0].Name);
3297+
Assert.Equal(3, Convert.ToInt32(traces[0].Result));
3298+
Assert.Equal(2, traces[1].Args.Length);
3299+
Assert.Equal(1, Convert.ToInt32(traces[1].Args[0]));
3300+
Assert.Equal(2, Convert.ToInt32(traces[1].Args[1]));
3301+
Assert.Equal(1, traces[0].StartLine);
3302+
Assert.Equal(3, traces[0].EndLine);
3303+
}
3304+
3305+
private class FunctionCallRecord
3306+
{
3307+
public string Name { get; set; }
3308+
public int StartLine { get; set; }
3309+
public int EndLine { get; set; }
3310+
public object[] Args { get; set; }
3311+
public object Result { get; set; }
3312+
}
32543313
}
32553314
}

Jint/Native/Function/ScriptFunctionInstance.cs

+10-1
Original file line numberDiff line numberDiff line change
@@ -75,8 +75,17 @@ protected internal override JsValue Call(JsValue thisArgument, JsValue[] argumen
7575

7676
// actual call
7777
var context = _engine._activeEvaluationContext ?? new EvaluationContext(_engine);
78-
78+
//Guid? traceId = null;
79+
//if (context.Engine.Options.Interop.FunctionExecuting is { } executing)
80+
//{
81+
// traceId = Guid.NewGuid();
82+
// executing(context.Engine, this, _functionDefinition.Function, arguments, traceId.Value);
83+
//}
7984
var result = _functionDefinition.EvaluateBody(context, this, arguments);
85+
//if (traceId.HasValue && context.Engine.Options.Interop.FunctionExecuted is { } executed)
86+
//{
87+
// executed(result, traceId.Value);
88+
//}
8089

8190
if (result.Type == CompletionType.Throw)
8291
{

Jint/Options.cs

+8-2
Original file line numberDiff line numberDiff line change
@@ -2,14 +2,16 @@
22
using System.Globalization;
33
using System.Linq;
44
using System.Reflection;
5+
using Esprima.Ast;
56
using Jint.Native;
7+
using Jint.Native.Function;
68
using Jint.Native.Object;
79
using Jint.Runtime;
8-
using Jint.Runtime.Interop;
10+
using Jint.Runtime.CallStack;
911
using Jint.Runtime.Debugger;
1012
using Jint.Runtime.Descriptors;
13+
using Jint.Runtime.Interop;
1114
using Jint.Runtime.Modules;
12-
using Jint.Runtime.CallStack;
1315

1416
namespace Jint
1517
{
@@ -334,6 +336,10 @@ public class InteropOptions
334336
/// </summary>
335337
public Func<object, string>? SerializeToJson { get; set; }
336338

339+
public Action<Engine, FunctionInstance, IFunction, JsValue[], Guid>? FunctionExecuting { get; set; }
340+
341+
public Action<Completion, Guid>? FunctionExecuted { get; set; }
342+
337343
/// <summary>
338344
/// What kind of date time should be produced when JavaScript date is converted to DateTime. If Local, uses <see cref="Options.TimeZone"/>.
339345
/// Defaults to <see cref="System.DateTimeKind.Utc"/>.
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,22 @@
1+
using Esprima.Ast;
2+
using Jint.Native;
3+
using Jint.Native.Function;
4+
5+
#nullable disable
6+
7+
namespace Jint.Runtime.Interop.Function;
8+
9+
public class FunctionExecutingContext
10+
{
11+
public Guid TraceId { get; set; }
12+
public Engine Engine { get; set; }
13+
public IFunction Function { get; set; }
14+
public FunctionInstance FunctionInstance { get; set; }
15+
public JsValue[] Arguments { get; set; }
16+
}
17+
18+
public class FunctionExecutedContext
19+
{
20+
public Guid TraceId { get; set; }
21+
public Completion? Result { get; set; }
22+
}

Jint/Runtime/Interpreter/JintFunctionDefinition.cs

+1-1
Original file line numberDiff line numberDiff line change
@@ -415,7 +415,7 @@ private static void ProcessParameters(
415415
out bool hasArguments)
416416
{
417417
hasArguments = false;
418-
state.IsSimpleParameterList = true;
418+
state.IsSimpleParameterList = true;
419419

420420
var countParameters = true;
421421
ref readonly var functionDeclarationParams = ref function.Params;

0 commit comments

Comments
 (0)