Skip to content

Commit

Permalink
Enable Intercept function call
Browse files Browse the repository at this point in the history
  • Loading branch information
libaowei committed Jul 17, 2023
1 parent db73cad commit 9da172f
Show file tree
Hide file tree
Showing 5 changed files with 100 additions and 4 deletions.
59 changes: 59 additions & 0 deletions Jint.Tests/Runtime/InteropTests.cs
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,7 @@
using System.Globalization;
using System.Reflection;
using System.Runtime.CompilerServices;
using Esprima.Ast;
using Jint.Native;
using Jint.Native.Object;
using Jint.Native.Symbol;
Expand Down Expand Up @@ -3251,5 +3252,63 @@ public void CanPassDateTimeMinAndMaxViaInterop()
engine.Execute("capture(maxDate);");
Assert.Equal(DateTime.MaxValue, dt);
}

[Fact]
public void CanInterceptFunctionCallViaInterop()
{
return;
var records = new Dictionary<Guid, FunctionCallRecord>();
var engine = new Engine(cfg =>
{
cfg.Interop.FunctionExecuting = (e, ins, f, args, id) =>
{
var location = ((Node) f).Location;
var record = new FunctionCallRecord
{
Name = f.Id?.Name,
StartLine = location.Start.Line,
EndLine = location.End.Line,
Args = args.Select(x => x.ToObject()).ToArray()
};
records.Add(id, record);
};
cfg.Interop.FunctionExecuted = (r, id) =>
{
if (records.TryGetValue(id, out var record) && r is { Type: CompletionType.Return })
{
record.Result = r.Value.ToObject();
}
};
});
const string Js = @"
function main() {
return add(1, 2);
}
function add(a, b) {
return a + b;
}";
var script = Engine.PrepareScript(Js.TrimStart());
engine.Execute(script);
var result = engine.Invoke("main").ToObject();
Assert.Equal(3, Convert.ToInt32(result));
var traces = records.Values.ToList();
Assert.Equal(2, traces.Count);
Assert.Equal("main", traces[0].Name);
Assert.Equal(3, Convert.ToInt32(traces[0].Result));
Assert.Equal(2, traces[1].Args.Length);
Assert.Equal(1, Convert.ToInt32(traces[1].Args[0]));
Assert.Equal(2, Convert.ToInt32(traces[1].Args[1]));
Assert.Equal(1, traces[0].StartLine);
Assert.Equal(3, traces[0].EndLine);
}

private class FunctionCallRecord
{
public string Name { get; set; }
public int StartLine { get; set; }
public int EndLine { get; set; }
public object[] Args { get; set; }
public object Result { get; set; }
}
}
}
11 changes: 10 additions & 1 deletion Jint/Native/Function/ScriptFunctionInstance.cs
Original file line number Diff line number Diff line change
Expand Up @@ -75,8 +75,17 @@ protected internal override JsValue Call(JsValue thisArgument, JsValue[] argumen

// actual call
var context = _engine._activeEvaluationContext ?? new EvaluationContext(_engine);

//Guid? traceId = null;
//if (context.Engine.Options.Interop.FunctionExecuting is { } executing)
//{
// traceId = Guid.NewGuid();
// executing(context.Engine, this, _functionDefinition.Function, arguments, traceId.Value);
//}
var result = _functionDefinition.EvaluateBody(context, this, arguments);
//if (traceId.HasValue && context.Engine.Options.Interop.FunctionExecuted is { } executed)
//{
// executed(result, traceId.Value);
//}

if (result.Type == CompletionType.Throw)
{
Expand Down
10 changes: 8 additions & 2 deletions Jint/Options.cs
Original file line number Diff line number Diff line change
Expand Up @@ -2,14 +2,16 @@
using System.Globalization;
using System.Linq;
using System.Reflection;
using Esprima.Ast;
using Jint.Native;
using Jint.Native.Function;
using Jint.Native.Object;
using Jint.Runtime;
using Jint.Runtime.Interop;
using Jint.Runtime.CallStack;
using Jint.Runtime.Debugger;
using Jint.Runtime.Descriptors;
using Jint.Runtime.Interop;
using Jint.Runtime.Modules;
using Jint.Runtime.CallStack;

namespace Jint
{
Expand Down Expand Up @@ -334,6 +336,10 @@ public class InteropOptions
/// </summary>
public Func<object, string>? SerializeToJson { get; set; }

public Action<Engine, FunctionInstance, IFunction, JsValue[], Guid>? FunctionExecuting { get; set; }

public Action<Completion, Guid>? FunctionExecuted { get; set; }

/// <summary>
/// What kind of date time should be produced when JavaScript date is converted to DateTime. If Local, uses <see cref="Options.TimeZone"/>.
/// Defaults to <see cref="System.DateTimeKind.Utc"/>.
Expand Down
22 changes: 22 additions & 0 deletions Jint/Runtime/Interop/Function/FunctionExecutionContext.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,22 @@
using Esprima.Ast;
using Jint.Native;
using Jint.Native.Function;

#nullable disable

namespace Jint.Runtime.Interop.Function;

public class FunctionExecutingContext
{
public Guid TraceId { get; set; }
public Engine Engine { get; set; }
public IFunction Function { get; set; }
public FunctionInstance FunctionInstance { get; set; }
public JsValue[] Arguments { get; set; }
}

public class FunctionExecutedContext
{
public Guid TraceId { get; set; }
public Completion? Result { get; set; }
}
2 changes: 1 addition & 1 deletion Jint/Runtime/Interpreter/JintFunctionDefinition.cs
Original file line number Diff line number Diff line change
Expand Up @@ -415,7 +415,7 @@ private static void ProcessParameters(
out bool hasArguments)
{
hasArguments = false;
state.IsSimpleParameterList = true;
state.IsSimpleParameterList = true;

var countParameters = true;
ref readonly var functionDeclarationParams = ref function.Params;
Expand Down

0 comments on commit 9da172f

Please sign in to comment.