Browse Source

Bound function should not inherit from FunctionInstance (#1044)

Marko Lahma 3 years ago
parent
commit
f2e440463f

+ 39 - 17
Jint/Native/Function/BindFunctionInstance.cs

@@ -3,24 +3,46 @@ using Jint.Runtime;
 
 
 namespace Jint.Native.Function
 namespace Jint.Native.Function
 {
 {
-    public sealed class BindFunctionInstance : FunctionInstance, IConstructor
+    /// <summary>
+    /// https://tc39.es/ecma262/#sec-bound-function-exotic-objects
+    /// </summary>
+    internal sealed class BindFunctionInstance : ObjectInstance, IConstructor, ICallable
     {
     {
-        public BindFunctionInstance(
-            Engine engine,
-            Realm realm)
-            : base(engine, realm, name: null, thisMode: FunctionThisMode.Strict)
+        private readonly Realm _realm;
+
+        public BindFunctionInstance(Engine engine,
+            Realm realm,
+            ObjectInstance proto,
+            ObjectInstance targetFunction,
+            JsValue boundThis,
+            JsValue[] boundArgs)
+            : base(engine, ObjectClass.Function)
         {
         {
+            _realm = realm;
+            _prototype = proto;
+            BoundTargetFunction = targetFunction;
+            BoundThis = boundThis;
+            BoundArguments = boundArgs;
         }
         }
 
 
-        public JsValue TargetFunction { get; set; }
+        /// <summary>
+        /// The wrapped function object.
+        /// </summary>
+        public JsValue BoundTargetFunction { get; }
 
 
-        public JsValue BoundThis { get; set; }
+        /// <summary>
+        /// The value that is always passed as the this value when calling the wrapped function.
+        /// </summary>
+        public JsValue BoundThis { get; }
 
 
-        public JsValue[] BoundArgs { get; set; }
+        /// <summary>
+        /// A list of values whose elements are used as the first arguments to any call to the wrapped function.
+        /// </summary>
+        public JsValue[] BoundArguments { get; }
 
 
-        public override JsValue Call(JsValue thisObject, JsValue[] arguments)
+        public JsValue Call(JsValue thisObject, JsValue[] arguments)
         {
         {
-            var f = TargetFunction as FunctionInstance;
+            var f = BoundTargetFunction as FunctionInstance;
             if (f is null)
             if (f is null)
             {
             {
                 ExceptionHelper.ThrowTypeError(_realm);
                 ExceptionHelper.ThrowTypeError(_realm);
@@ -35,7 +57,7 @@ namespace Jint.Native.Function
 
 
         public ObjectInstance Construct(JsValue[] arguments, JsValue newTarget)
         public ObjectInstance Construct(JsValue[] arguments, JsValue newTarget)
         {
         {
-            var target = TargetFunction as IConstructor;
+            var target = BoundTargetFunction as IConstructor;
             if (target is null)
             if (target is null)
             {
             {
                 ExceptionHelper.ThrowTypeError(_realm);
                 ExceptionHelper.ThrowTypeError(_realm);
@@ -45,7 +67,7 @@ namespace Jint.Native.Function
 
 
             if (ReferenceEquals(this, newTarget))
             if (ReferenceEquals(this, newTarget))
             {
             {
-                newTarget = TargetFunction;
+                newTarget = BoundTargetFunction;
             }
             }
 
 
             var value = target.Construct(args, newTarget);
             var value = target.Construct(args, newTarget);
@@ -56,7 +78,7 @@ namespace Jint.Native.Function
 
 
         internal override bool OrdinaryHasInstance(JsValue v)
         internal override bool OrdinaryHasInstance(JsValue v)
         {
         {
-            var f = TargetFunction as FunctionInstance;
+            var f = BoundTargetFunction as FunctionInstance;
             if (f is null)
             if (f is null)
             {
             {
                 ExceptionHelper.ThrowTypeError(_realm);
                 ExceptionHelper.ThrowTypeError(_realm);
@@ -67,13 +89,13 @@ namespace Jint.Native.Function
 
 
         private JsValue[] CreateArguments(JsValue[] arguments)
         private JsValue[] CreateArguments(JsValue[] arguments)
         {
         {
-            var combined = _engine._jsValueArrayPool.RentArray(BoundArgs.Length + arguments.Length);
-            System.Array.Copy(BoundArgs, combined, BoundArgs.Length);
-            System.Array.Copy(arguments, 0, combined, BoundArgs.Length, arguments.Length);
+            var combined = _engine._jsValueArrayPool.RentArray(BoundArguments.Length + arguments.Length);
+            System.Array.Copy(BoundArguments, combined, BoundArguments.Length);
+            System.Array.Copy(arguments, 0, combined, BoundArguments.Length, arguments.Length);
             return combined;
             return combined;
         }
         }
 
 
-        internal override bool IsConstructor => TargetFunction.IsConstructor;
+        internal override bool IsConstructor => BoundTargetFunction.IsConstructor;
 
 
         public override string ToString() => "function () { [native code] }";
         public override string ToString() => "function () { [native code] }";
     }
     }

+ 1 - 1
Jint/Native/Function/FunctionInstance.cs

@@ -280,7 +280,7 @@ namespace Jint.Native.Function
 
 
             if (obj is BindFunctionInstance bindFunctionInstance)
             if (obj is BindFunctionInstance bindFunctionInstance)
             {
             {
-                return GetFunctionRealm(bindFunctionInstance.TargetFunction);
+                return GetFunctionRealm(bindFunctionInstance.BoundTargetFunction);
             }
             }
 
 
             if (obj is ProxyInstance proxyInstance)
             if (obj is ProxyInstance proxyInstance)

+ 4 - 15
Jint/Native/Function/FunctionPrototype.cs

@@ -48,12 +48,7 @@ namespace Jint.Native.Function
 
 
         private static JsValue HasInstance(JsValue thisObj, JsValue[] arguments)
         private static JsValue HasInstance(JsValue thisObj, JsValue[] arguments)
         {
         {
-            if (thisObj is not FunctionInstance f)
-            {
-                return false;
-            }
-
-            return f.OrdinaryHasInstance(arguments.At(0));
+            return thisObj.OrdinaryHasInstance(arguments.At(0));
         }
         }
 
 
         private JsValue Bind(JsValue thisObj, JsValue[] arguments)
         private JsValue Bind(JsValue thisObj, JsValue[] arguments)
@@ -88,7 +83,7 @@ namespace Jint.Native.Function
                 l = JsNumber.PositiveZero;
                 l = JsNumber.PositiveZero;
             }
             }
 
 
-            f._length = new PropertyDescriptor(l, PropertyFlag.Configurable);
+            f.DefinePropertyOrThrow(CommonProperties.Length, new PropertyDescriptor(l, PropertyFlag.Configurable));
 
 
             var targetName = thisObj.Get(CommonProperties.Name);
             var targetName = thisObj.Get(CommonProperties.Name);
             if (!targetName.IsString())
             if (!targetName.IsString())
@@ -104,16 +99,10 @@ namespace Jint.Native.Function
         /// <summary>
         /// <summary>
         /// https://tc39.es/ecma262/#sec-boundfunctioncreate
         /// https://tc39.es/ecma262/#sec-boundfunctioncreate
         /// </summary>
         /// </summary>
-        private FunctionInstance BoundFunctionCreate(ObjectInstance targetFunction, JsValue boundThis, JsValue[] boundArgs)
+        private BindFunctionInstance BoundFunctionCreate(ObjectInstance targetFunction, JsValue boundThis, JsValue[] boundArgs)
         {
         {
             var proto = targetFunction.GetPrototypeOf();
             var proto = targetFunction.GetPrototypeOf();
-            var obj = new BindFunctionInstance(_engine, _realm)
-            {
-                _prototype = proto,
-                TargetFunction = targetFunction,
-                BoundThis = boundThis,
-                BoundArgs = boundArgs
-            };
+            var obj = new BindFunctionInstance(_engine, _realm, proto, targetFunction, boundThis, boundArgs);
             return obj;
             return obj;
         }
         }
 
 

+ 19 - 0
Jint/Native/Object/ObjectInstance.cs

@@ -1172,6 +1172,25 @@ namespace Jint.Native.Object
             return true;
             return true;
         }
         }
 
 
+        /// <summary>
+        /// https://tc39.es/ecma262/#sec-setfunctionname
+        /// </summary>
+        internal void SetFunctionName(JsValue name, string prefix = null)
+        {
+            if (name is JsSymbol symbol)
+            {
+                name = symbol._value.IsUndefined()
+                    ? JsString.Empty
+                    : new JsString("[" + symbol._value + "]");
+            }
+            if (!string.IsNullOrWhiteSpace(prefix))
+            {
+                name = prefix + " " + name;
+            }
+
+            DefinePropertyOrThrow(CommonProperties.Name, new PropertyDescriptor(name, PropertyFlag.Configurable));
+        }
+
         /// <summary>
         /// <summary>
         /// https://tc39.es/ecma262/#sec-createmethodproperty
         /// https://tc39.es/ecma262/#sec-createmethodproperty
         /// </summary>
         /// </summary>