Browse Source

Reset constraints between Engine.Invoke calls (#986)

Marko Lahma 3 years ago
parent
commit
744e9edaa6
2 changed files with 82 additions and 47 deletions
  1. 39 0
      Jint.Tests/Runtime/ExecutionConstraintTests.cs
  2. 43 47
      Jint/Engine.cs

+ 39 - 0
Jint.Tests/Runtime/ExecutionConstraintTests.cs

@@ -1,5 +1,8 @@
 using System;
 using System;
+using System.Collections.Generic;
+using System.Linq;
 using System.Threading;
 using System.Threading;
+using Jint.Native.Function;
 using Jint.Runtime;
 using Jint.Runtime;
 using Xunit;
 using Xunit;
 
 
@@ -279,5 +282,41 @@ myarr[0](0);
             var engine = new Engine(o => o.MaxStatements(1_000).MaxArraySize(1_000_000));
             var engine = new Engine(o => o.MaxStatements(1_000).MaxArraySize(1_000_000));
             Assert.Throws<MemoryLimitExceededException>(() => engine.Evaluate("new Array(2147483647).join('*')"));
             Assert.Throws<MemoryLimitExceededException>(() => engine.Evaluate("new Array(2147483647).join('*')"));
         }
         }
+
+        [Fact]
+        public void ShouldConsiderConstraintsWhenCallingInvoke()
+        {
+            var engine = new Engine(options =>
+            {
+                options.TimeoutInterval(TimeSpan.FromMilliseconds(100));
+            });
+            var myApi = new MyApi();
+
+            engine.SetValue("myApi", myApi);
+            engine.Execute("myApi.addEventListener('DataReceived', (data) => { myApi.log(data) })");
+
+            var dataReceivedCallbacks = myApi.Callbacks.Where(kvp => kvp.Key == "DataReceived");
+            foreach (var callback in dataReceivedCallbacks)
+            {
+                engine.Invoke(callback.Value, "Data Received #1");
+                Thread.Sleep(101);
+                engine.Invoke(callback.Value, "Data Received #2");
+            }
+        }
+
+        private class MyApi
+        {
+            public readonly Dictionary<string, ScriptFunctionInstance> Callbacks = new Dictionary<string, ScriptFunctionInstance>();
+
+            public void AddEventListener(string eventName, ScriptFunctionInstance callback)
+            {
+                Callbacks.Add(eventName, callback);
+            }
+
+            public void Log(string logMessage)
+            {
+                Console.WriteLine(logMessage);
+            }
+        }
     }
     }
 }
 }

+ 43 - 47
Jint/Engine.cs

@@ -266,63 +266,46 @@ namespace Jint
 
 
         public Engine Execute(Script script)
         public Engine Execute(Script script)
         {
         {
-            var ownsContext = _activeEvaluationContext is null;
-            _activeEvaluationContext ??= new EvaluationContext(this);
-
-            ResetConstraints();
-
-            using (new StrictModeScope(_isStrict || script.Strict))
+            Engine DoInvoke()
             {
             {
-                GlobalDeclarationInstantiation(
-                    script,
-                    Realm.GlobalEnv);
-
-                var list = new JintStatementList(null, script.Body);
-
-                Completion result;
-                try
+                using (new StrictModeScope(_isStrict || script.Strict))
                 {
                 {
-                    result = list.Execute(_activeEvaluationContext);
-                }
-                catch
-                {
-                    // unhandled exception
-                    ResetCallStack();
+                    GlobalDeclarationInstantiation(
+                        script,
+                        Realm.GlobalEnv);
+
+                    var list = new JintStatementList(null, script.Body);
 
 
-                    if (ownsContext)
+                    Completion result;
+                    try
                     {
                     {
-                        _activeEvaluationContext = null;
+                        result = list.Execute(_activeEvaluationContext);
                     }
                     }
-
-                    throw;
-                }
-
-                if (result.Type == CompletionType.Throw)
-                {
-                    var ex = new JavaScriptException(result.GetValueOrDefault())
-                        .SetCallstack(this, result.Location);
-                    ResetCallStack();
-
-                    if (ownsContext)
+                    catch
                     {
                     {
-                        _activeEvaluationContext = null;
+                        // unhandled exception
+                        ResetCallStack();
+                        throw;
                     }
                     }
 
 
-                    throw ex;
-                }
+                    if (result.Type == CompletionType.Throw)
+                    {
+                        var ex = new JavaScriptException(result.GetValueOrDefault()).SetCallstack(this, result.Location);
+                        ResetCallStack();
+                        throw ex;
+                    }
 
 
-                // TODO what about callstack and thrown exceptions?
-                RunAvailableContinuations(_eventLoop);
+                    // TODO what about callstack and thrown exceptions?
+                    RunAvailableContinuations(_eventLoop);
 
 
-                _completionValue = result.GetValueOrDefault();
+                    _completionValue = result.GetValueOrDefault();
 
 
-                if (ownsContext)
-                {
-                    _activeEvaluationContext = null;
+                    return this;
                 }
                 }
-
             }
             }
 
 
+            ExecuteWithConstraints(DoInvoke);
+
             return this;
             return this;
         }
         }
 
 
@@ -634,10 +617,7 @@ namespace Jint
                 ExceptionHelper.ThrowTypeError(Realm, "Can only invoke functions");
                 ExceptionHelper.ThrowTypeError(Realm, "Can only invoke functions");
             }
             }
 
 
-            var ownsContext = _activeEvaluationContext is null;
-            _activeEvaluationContext ??= new EvaluationContext(this);
-
-            try
+            JsValue DoInvoke()
             {
             {
                 var items = _jsValueArrayPool.RentArray(arguments.Length);
                 var items = _jsValueArrayPool.RentArray(arguments.Length);
                 for (var i = 0; i < arguments.Length; ++i)
                 for (var i = 0; i < arguments.Length; ++i)
@@ -649,12 +629,28 @@ namespace Jint
                 _jsValueArrayPool.ReturnArray(items);
                 _jsValueArrayPool.ReturnArray(items);
                 return result;
                 return result;
             }
             }
+
+            return ExecuteWithConstraints(DoInvoke);
+        }
+
+        private T ExecuteWithConstraints<T>(Func<T> callback)
+        {
+            ResetConstraints();
+
+            var ownsContext = _activeEvaluationContext is null;
+            _activeEvaluationContext ??= new EvaluationContext(this);
+
+            try
+            {
+                return callback();
+            }
             finally
             finally
             {
             {
                 if (ownsContext)
                 if (ownsContext)
                 {
                 {
                     _activeEvaluationContext = null;
                     _activeEvaluationContext = null;
                 }
                 }
+                ResetConstraints();
             }
             }
         }
         }