Browse Source

Cleanup ObjectInstance public API (#1720)

* Hide CanPut()
* Hide DefinePropertyOrThrow()
* Hide DeletePropertyOrThrow()
* Hide IsArray() from ObjectInstance and add JsValueExtensions.IsArray()
* Hide SetPrototypeOf() and allow set via Prototype property
* Make IsLooselyEqual() protected
* Hide IsArrayLike
* Only expose Length property for JsArray and JsTypedArray
* Remove Invoke
Marko Lahma 1 năm trước cách đây
mục cha
commit
69b33acaf3

+ 1 - 1
Jint.Tests.PublicInterface/RavenApiUsageTests.cs

@@ -231,7 +231,7 @@ file sealed class CustomString : JsString
         };
     }
 
-    public override bool IsLooselyEqual(JsValue value)
+    protected override bool IsLooselyEqual(JsValue value)
     {
         return value switch
         {

+ 1 - 1
Jint.Tests/Runtime/Debugger/DebugHandlerTests.cs

@@ -34,7 +34,7 @@ namespace Jint.Tests.Runtime.Debugger
                     var obj = info.CurrentScopeChain[0].GetBindingValue("obj") as ObjectInstance;
                     var prop = obj.GetOwnProperty("name");
                     // This is where reentrance would occur:
-                    var value = prop.Get.Invoke(engine);
+                    var value = engine.Invoke(prop.Get);
                     didPropertyAccess = true;
                 }
                 return StepMode.Into;

+ 6 - 6
Jint.Tests/Runtime/EngineTests.cs

@@ -832,7 +832,7 @@ namespace Jint.Tests.Runtime
 
             var add = _engine.GetValue("add");
 
-            Assert.Equal(3, add.Invoke(_engine, 1, 2));
+            Assert.Equal(3, _engine.Invoke(add, 1, 2));
         }
 
         [Fact]
@@ -844,7 +844,7 @@ namespace Jint.Tests.Runtime
 
             var add = _engine.GetValue("get");
             string str = null;
-            Assert.Equal(Native.JsValue.Null, add.Invoke(_engine, str));
+            Assert.Equal(Native.JsValue.Null, _engine.Invoke(add, str));
         }
 
 
@@ -857,7 +857,7 @@ namespace Jint.Tests.Runtime
 
             var x = _engine.GetValue("x");
 
-            var exception = Assert.Throws<JavaScriptException>(() => x.Invoke(_engine, 1, 2));
+            var exception = Assert.Throws<JavaScriptException>(() => _engine.Invoke(x, 1, 2));
             Assert.Equal("Can only invoke functions", exception.Message);
         }
 
@@ -2575,7 +2575,7 @@ var prep = function (fn) { fn(); };
                 }");
 
             var concat = _engine.GetValue("concat");
-            var result = concat.Invoke(_engine, "concat", "well", "done").ToObject() as string;
+            var result = _engine.Invoke(concat, "concat", "well", "done").ToObject() as string;
             Assert.Equal("concatwelldone", result);
         }
 
@@ -2709,10 +2709,10 @@ function output(x) {
             ");
 
             var function = _engine.GetValue("f");
-            var result = function.Invoke(_engine, 3).ToString();
+            var result = _engine.Invoke(function, 3).ToString();
             Assert.Equal("15", result);
 
-            result = function.Invoke(_engine, 3, JsValue.Undefined).ToString();
+            result = _engine.Invoke(function, 3, JsValue.Undefined).ToString();
             Assert.Equal("15", result);
         }
 

+ 1 - 1
Jint.Tests/Runtime/FunctionTests.cs

@@ -111,7 +111,7 @@ assertEqual(booleanCount, 1);
         Assert.Equal("abc", instanceFromFunction.Get("a"));
         Assert.Equal(123, instanceFromFunction.Get("b"));
 
-        var arrayInstance = (ArrayInstance) _engine.Construct("Array", "abc", 123).AsObject();
+        var arrayInstance = (JsArray) _engine.Construct("Array", "abc", 123).AsObject();
         Assert.Equal((uint) 2, arrayInstance.Length);
         Assert.Equal("abc", arrayInstance[0]);
         Assert.Equal(123, arrayInstance[1]);

+ 2 - 2
Jint.Tests/Runtime/InteropTests.cs

@@ -2358,7 +2358,7 @@ namespace Jint.Tests.Runtime
             ");
 
             Assert.NotNull(c.ToString());
-            Assert.Equal((uint) 0, c.As<ObjectInstance>().Length);
+            Assert.Equal((uint) 0, c.AsObject().GetLength());
         }
 
         private class DictionaryWrapper
@@ -2887,7 +2887,7 @@ namespace Jint.Tests.Runtime
         {
             var engine = new Engine(options =>
             {
-                options.Interop.CreateClrObject = oi => new Dictionary<string, object>((int) oi.Length);
+                options.Interop.CreateClrObject = oi => new Dictionary<string, object>();
             });
 
             object capture = null;

+ 1 - 1
Jint.Tests/Runtime/RegExpTests.cs

@@ -35,7 +35,7 @@ public class RegExpTests
     public void PreventsInfiniteLoop()
     {
         var engine = new Engine();
-        var result = (ArrayInstance) engine.Evaluate("'x'.match(/|/g);");
+        var result = (JsArray) engine.Evaluate("'x'.match(/|/g);");
         Assert.Equal((uint) 2, result.Length);
         Assert.Equal("", result[0]);
         Assert.Equal("", result[1]);

+ 8 - 0
Jint/JsValueExtensions.cs

@@ -29,6 +29,14 @@ public static class JsValueExtensions
         return value._type == InternalTypes.Undefined;
     }
 
+
+    [Pure]
+    [MethodImpl(MethodImplOptions.AggressiveInlining)]
+    public static bool IsArray(this JsValue value)
+    {
+        return value is JsArray;
+    }
+
     [Pure]
     [MethodImpl(MethodImplOptions.AggressiveInlining)]
     internal static bool IsNullOrUndefined(this JsValue value)

+ 3 - 5
Jint/Native/Array/ArrayInstance.cs

@@ -65,9 +65,9 @@ namespace Jint.Native.Array
             }
         }
 
-        public sealed override bool IsArrayLike => true;
+        internal sealed override bool IsArrayLike => true;
 
-        public sealed override bool IsArray() => true;
+        internal sealed override bool IsArray() => true;
 
         internal sealed override bool HasOriginalIterator
             => ReferenceEquals(Get(GlobalSymbolRegistry.Iterator), _constructor?.PrototypeObject._originalIteratorFunction);
@@ -287,7 +287,7 @@ namespace Jint.Native.Array
         }
 
         [MethodImpl(MethodImplOptions.AggressiveInlining)]
-        internal uint GetLength() => (uint) GetJsNumberLength()._value;
+        internal override uint GetLength() => (uint) GetJsNumberLength()._value;
 
         [MethodImpl(MethodImplOptions.AggressiveInlining)]
         private JsNumber GetJsNumberLength() => _length is null ? JsNumber.PositiveZero : (JsNumber) _length._value!;
@@ -1267,8 +1267,6 @@ namespace Jint.Native.Array
             return false;
         }
 
-        public sealed override uint Length => GetLength();
-
         internal sealed override bool IsIntegerIndexedArray => true;
 
         public JsValue this[uint index]

+ 2 - 2
Jint/Native/Array/ArrayIteratorPrototype.cs

@@ -61,7 +61,7 @@ internal sealed class ArrayIteratorPrototype : IteratorPrototype
 
         public override bool TryIteratorStep(out ObjectInstance nextItem)
         {
-            var len = _array.Length;
+            var len = _array.GetLength();
             var position = _position;
             if (!_closed && position < len)
             {
@@ -109,7 +109,7 @@ internal sealed class ArrayIteratorPrototype : IteratorPrototype
             if (_typedArray is not null)
             {
                 _typedArray._viewedArrayBuffer.AssertNotDetached();
-                len = _typedArray.Length;
+                len = _typedArray.GetLength();
             }
             else
             {

+ 2 - 2
Jint/Native/Array/ArrayOperations.cs

@@ -291,7 +291,7 @@ namespace Jint.Native.Array
             {
                 if (!_target.IsConcatSpreadable)
                 {
-                    return _target.Length;
+                    return _target.GetLength();
                 }
 
                 var descValue = _target.Get(CommonProperties.Length);
@@ -317,7 +317,7 @@ namespace Jint.Native.Array
 
             public override bool TryGetValue(ulong index, out JsValue value)
             {
-                if (index < _target.Length)
+                if (index < _target.GetLength())
                 {
                     value = _target[(int) index];
                     return true;

+ 3 - 3
Jint/Native/Array/ArrayPrototype.cs

@@ -547,7 +547,7 @@ namespace Jint.Native.Array
             var mapperFunction = arguments.At(0);
             var thisArg = arguments.At(1);
 
-            var sourceLen = O.Length;
+            var sourceLen = O.GetLength();
 
             if (!mapperFunction.IsCallable)
             {
@@ -608,7 +608,7 @@ namespace Jint.Native.Array
                             : depth - 1;
 
                         var objectInstance = (ObjectInstance) element;
-                        var elementLen = objectInstance.Length;
+                        var elementLen = objectInstance.GetLength();
                         targetIndex = FlattenIntoArray(target, objectInstance, elementLen, targetIndex, newDepth);
                     }
                     else
@@ -866,7 +866,7 @@ namespace Jint.Native.Array
         private JsValue At(JsValue thisObject, JsValue[] arguments)
         {
             var target = TypeConverter.ToObject(_realm, thisObject);
-            var len = target.Length;
+            var len = target.GetLength();
             var relativeIndex = TypeConverter.ToInteger(arguments.At(0));
 
             ulong actualIndex;

+ 4 - 2
Jint/Native/JsArray.cs

@@ -24,7 +24,9 @@ public sealed class JsArray : ArrayInstance
     public JsArray(Engine engine, JsValue[] items) : base(engine, items)
     {
     }
-    
+
+    public uint Length => GetLength();
+
     private sealed class JsArrayDebugView
     {
         private readonly JsArray _array;
@@ -39,7 +41,7 @@ public sealed class JsArray : ArrayInstance
         {
             get
             {
-                var values = new JsValue[_array.Length];
+                var values = new JsValue[_array.GetLength()];
                 var i = 0;
                 foreach (var value in _array)
                 {

+ 1 - 1
Jint/Native/JsBigInt.cs

@@ -65,7 +65,7 @@ public sealed class JsBigInt : JsValue, IEquatable<JsBigInt>
         return TypeConverter.ToString(_value);
     }
 
-    public override bool IsLooselyEqual(JsValue value)
+    protected internal override bool IsLooselyEqual(JsValue value)
     {
         if (value is JsBigInt bigInt)
         {

+ 1 - 1
Jint/Native/JsBoolean.cs

@@ -28,7 +28,7 @@ public sealed class JsBoolean : JsValue, IEquatable<JsBoolean>
         return _value ? "true" : "false";
     }
 
-    public override bool IsLooselyEqual(JsValue value)
+    protected internal override bool IsLooselyEqual(JsValue value)
     {
         if (value is JsBoolean jsBoolean)
         {

+ 1 - 1
Jint/Native/JsNull.cs

@@ -13,7 +13,7 @@ public sealed class JsNull : JsValue, IEquatable<JsNull>
 
     public override string ToString() => "null";
 
-    public override bool IsLooselyEqual(JsValue value)
+    protected internal override bool IsLooselyEqual(JsValue value)
     {
         return ReferenceEquals(Null, value) || ReferenceEquals(Undefined, value);
     }

+ 1 - 1
Jint/Native/JsNumber.cs

@@ -251,7 +251,7 @@ public sealed class JsNumber : JsValue, IEquatable<JsNumber>
         return double.IsNegativeInfinity(_value);
     }
 
-    public override bool IsLooselyEqual(JsValue value)
+    protected internal override bool IsLooselyEqual(JsValue value)
     {
         if (value is JsNumber jsNumber)
         {

+ 1 - 1
Jint/Native/JsString.cs

@@ -307,7 +307,7 @@ public class JsString : JsValue, IEquatable<JsString>, IEquatable<string>
         return string.Equals(_value, other.ToString(), StringComparison.Ordinal);
     }
 
-    public override bool IsLooselyEqual(JsValue value)
+    protected internal override bool IsLooselyEqual(JsValue value)
     {
         if (value is JsString jsString)
         {

+ 1 - 1
Jint/Native/JsUndefined.cs

@@ -13,7 +13,7 @@ public sealed class JsUndefined : JsValue, IEquatable<JsUndefined>
 
     public override string ToString() => "undefined";
 
-    public override bool IsLooselyEqual(JsValue value)
+    protected internal override bool IsLooselyEqual(JsValue value)
     {
         return ReferenceEquals(Undefined, value) || ReferenceEquals(Null, value);
     }

+ 2 - 14
Jint/Native/JsValue.cs

@@ -32,7 +32,7 @@ namespace Jint.Native
         }
 
         [Pure]
-        public virtual bool IsArray() => false;
+        internal virtual bool IsArray() => false;
 
         [DebuggerBrowsable(DebuggerBrowsableState.Never)]
         internal virtual bool IsIntegerIndexedArray => false;
@@ -177,18 +177,6 @@ namespace Jint.Native
         /// </summary>
         internal virtual bool ToBoolean() => _type > InternalTypes.Null;
 
-        /// <summary>
-        /// Invoke the current value as function.
-        /// </summary>
-        /// <param name="engine">The engine handling the invoke.</param>
-        /// <param name="arguments">The arguments of the function call.</param>
-        /// <returns>The value returned by the function call.</returns>
-        [Obsolete("Should use Engine.Invoke when direct invoking is needed.")]
-        public JsValue Invoke(Engine engine, params JsValue[] arguments)
-        {
-            return engine.Invoke(this, arguments);
-        }
-
         /// <summary>
         /// https://tc39.es/ecma262/#sec-getv
         /// </summary>
@@ -315,7 +303,7 @@ namespace Jint.Native
         /// <summary>
         /// https://tc39.es/ecma262/#sec-islooselyequal
         /// </summary>
-        public virtual bool IsLooselyEqual(JsValue value)
+        protected internal virtual bool IsLooselyEqual(JsValue value)
         {
             if (ReferenceEquals(this, value))
             {

+ 1 - 1
Jint/Native/Json/JsonSerializer.cs

@@ -84,7 +84,7 @@ namespace Jint.Native.Json
                 if (oi.IsArray())
                 {
                     _propertyList = new List<JsValue>();
-                    var len = oi.Length;
+                    var len = oi.GetLength();
                     var k = 0;
                     while (k < len)
                     {

+ 13 - 10
Jint/Native/Object/ObjectInstance.cs

@@ -1,3 +1,4 @@
+using System.ComponentModel;
 using System.Diagnostics;
 using System.Diagnostics.CodeAnalysis;
 using System.Runtime.CompilerServices;
@@ -15,6 +16,8 @@ using Jint.Native.TypedArray;
 using Jint.Runtime;
 using Jint.Runtime.Descriptors;
 using Jint.Runtime.Interop;
+using PropertyDescriptor = Jint.Runtime.Descriptors.PropertyDescriptor;
+using TypeConverter = Jint.Runtime.TypeConverter;
 
 namespace Jint.Native.Object
 {
@@ -62,6 +65,7 @@ namespace Jint.Native.Object
         {
             [DebuggerStepThrough]
             get => GetPrototypeOf();
+            set => SetPrototypeOf(value!);
         }
 
         /// <summary>
@@ -629,7 +633,7 @@ namespace Jint.Native.Object
         /// performed.
         /// http://www.ecma-international.org/ecma-262/5.1/#sec-8.12.4
         /// </summary>
-        public bool CanPut(JsValue property)
+        internal bool CanPut(JsValue property)
         {
             var desc = GetOwnProperty(property);
 
@@ -704,7 +708,7 @@ namespace Jint.Native.Object
         /// <summary>
         /// https://tc39.es/ecma262/#sec-deletepropertyorthrow
         /// </summary>
-        public bool DeletePropertyOrThrow(JsValue property)
+        internal bool DeletePropertyOrThrow(JsValue property)
         {
             if (!Delete(property))
             {
@@ -736,7 +740,7 @@ namespace Jint.Native.Object
             return false;
         }
 
-        public bool DefinePropertyOrThrow(JsValue property, PropertyDescriptor desc)
+        internal bool DefinePropertyOrThrow(JsValue property, PropertyDescriptor desc)
         {
             if (!DefineOwnProperty(property, desc))
             {
@@ -1043,7 +1047,7 @@ namespace Jint.Native.Object
 
                     if (this is JsArray arrayInstance)
                     {
-                        var result = new object?[arrayInstance.Length];
+                        var result = new object?[arrayInstance.GetLength()];
                         for (uint i = 0; i < result.Length; i++)
                         {
                             var value = arrayInstance[i];
@@ -1225,9 +1229,9 @@ namespace Jint.Native.Object
         }
 
         [DebuggerBrowsable(DebuggerBrowsableState.Never)]
-        public virtual bool IsArrayLike => TryGetValue(CommonProperties.Length, out var lengthValue)
-                                           && lengthValue.IsNumber()
-                                           && ((JsNumber) lengthValue)._value >= 0;
+        internal virtual bool IsArrayLike => TryGetValue(CommonProperties.Length, out var lengthValue)
+                                             && lengthValue.IsNumber()
+                                             && ((JsNumber) lengthValue)._value >= 0;
 
         // safe default
         [DebuggerBrowsable(DebuggerBrowsableState.Never)]
@@ -1235,8 +1239,7 @@ namespace Jint.Native.Object
 
         internal override bool IsIntegerIndexedArray => false;
 
-        [DebuggerBrowsable(DebuggerBrowsableState.Never)]
-        public virtual uint Length => (uint) TypeConverter.ToLength(Get(CommonProperties.Length));
+        internal virtual uint GetLength() => (uint) TypeConverter.ToLength(Get(CommonProperties.Length));
 
         public virtual bool PreventExtensions()
         {
@@ -1252,7 +1255,7 @@ namespace Jint.Native.Object
         /// <summary>
         /// https://tc39.es/ecma262/#sec-ordinarysetprototypeof
         /// </summary>
-        public virtual bool SetPrototypeOf(JsValue value)
+        internal virtual bool SetPrototypeOf(JsValue value)
         {
             if (!value.IsObject() && !value.IsNull())
             {

+ 2 - 2
Jint/Native/Proxy/JsProxy.cs

@@ -94,7 +94,7 @@ namespace Jint.Native.Proxy
             return oi;
         }
 
-        public override bool IsArray()
+        internal override bool IsArray()
         {
             AssertNotRevoked(KeyIsArray);
             return _target.IsArray();
@@ -553,7 +553,7 @@ namespace Jint.Native.Proxy
         /// <summary>
         /// https://tc39.es/ecma262/#sec-proxy-object-internal-methods-and-internal-slots-setprototypeof-v
         /// </summary>
-        public override bool SetPrototypeOf(JsValue value)
+        internal override bool SetPrototypeOf(JsValue value)
         {
             if (!TryCallHandler(TrapSetProtoTypeOf, new[] { _target, value }, out var result))
             {

+ 1 - 1
Jint/Native/RegExp/RegExpPrototype.cs

@@ -239,7 +239,7 @@ namespace Jint.Native.RegExp
             for (var i = 0; i < results.Count; i++)
             {
                 var result = results[i];
-                var nCaptures = (int) result.Length;
+                var nCaptures = (int) result.GetLength();
                 nCaptures = System.Math.Max(nCaptures - 1, 0);
                 var matched = TypeConverter.ToString(result.Get(0));
                 var matchLength = matched.Length;

+ 2 - 2
Jint/Native/TypedArray/IntrinsicTypedArrayConstructor.cs

@@ -93,7 +93,7 @@ namespace Jint.Native.TypedArray
             }
 
             var arrayLike = TypeConverter.ToObject(_realm, source);
-            var len = arrayLike.Length;
+            var len = arrayLike.GetLength();
 
             var argumentList = new JsValue[] { JsNumber.Create(len) };
             var targetObj = TypedArrayCreate(_realm, (IConstructor) c, argumentList);
@@ -176,7 +176,7 @@ namespace Jint.Native.TypedArray
                 {
                     ExceptionHelper.ThrowTypeError(realm);
                 }
-                if (newTypedArray.Length < number._value)
+                if (newTypedArray.GetLength() < number._value)
                 {
                     ExceptionHelper.ThrowTypeError(realm);
                 }

+ 1 - 1
Jint/Native/TypedArray/IntrinsicTypedArrayPrototype.cs

@@ -1317,7 +1317,7 @@ namespace Jint.Native.TypedArray
             var end = arguments.At(1);
 
             var buffer = o._viewedArrayBuffer;
-            var srcLength = o.Length;
+            var srcLength = o.GetLength();
             var relativeBegin = TypeConverter.ToIntegerOrInfinity(begin);
 
             double beginIndex;

+ 5 - 3
Jint/Native/TypedArray/JsTypedArray.cs

@@ -53,7 +53,9 @@ namespace Jint.Native.TypedArray
             set => IntegerIndexedElementSet(index, value);
         }
 
-        public override uint Length => IntrinsicTypedArrayPrototype.MakeTypedArrayWithBufferWitnessRecord(this, ArrayBufferOrder.Unordered).TypedArrayLength;
+        public uint Length => GetLength();
+
+        internal override uint GetLength() => IntrinsicTypedArrayPrototype.MakeTypedArrayWithBufferWitnessRecord(this, ArrayBufferOrder.Unordered).TypedArrayLength;
 
         internal override bool IsIntegerIndexedArray => true;
 
@@ -196,7 +198,7 @@ namespace Jint.Native.TypedArray
             var keys = new List<JsValue>();
             if (!taRecord.IsTypedArrayOutOfBounds)
             {
-                var length = Length;
+                var length = GetLength();
                 for (uint i = 0; i < length; ++i)
                 {
                     keys.Add(JsString.Create(i));
@@ -390,7 +392,7 @@ namespace Jint.Native.TypedArray
             var byteOffset = _byteOffset;
             var buffer = _viewedArrayBuffer;
 
-            var array = new T[Length];
+            var array = new T[GetLength()];
             for (var i = 0; i < array.Length; ++i)
             {
                 var indexedPosition = i * elementSize + byteOffset;

+ 1 - 1
Jint/Runtime/Interop/DefaultTypeConverter.cs

@@ -270,7 +270,7 @@ namespace Jint.Runtime.Interop
                          arguments[i].GetCustomAttribute<ParamArrayAttribute>() is not null &&
                          function.Target is FunctionInstance instance)
                 {
-                    for (var j = 0; j < instance.Length; j++)
+                    for (var j = 0; j < instance.GetLength(); j++)
                     {
                         var returnLabel = Expression.Label(typeof(object));
                         var checkIndex = Expression.GreaterThanOrEqual(Expression.Property(param, nameof(Array.Length)), Expression.Constant(j));

+ 1 - 1
Jint/Runtime/Interop/ObjectWrapper.cs

@@ -35,7 +35,7 @@ namespace Jint.Runtime.Interop
         public object Target { get; }
         internal Type ClrType { get; }
 
-        public override bool IsArrayLike => _typeDescriptor.IsArrayLike;
+        internal override bool IsArrayLike => _typeDescriptor.IsArrayLike;
 
         internal override bool HasOriginalIterator => IsArrayLike;
 

+ 1 - 1
Jint/Runtime/Interpreter/Expressions/JintImportExpression.cs

@@ -59,7 +59,7 @@ internal sealed class JintImportExpression : JintExpression
                     }
 
                     var entries = oi.EnumerableOwnProperties(ObjectInstance.EnumerableOwnPropertyNamesKind.KeyValue);
-                    attributes.Capacity = (int) entries.Length;
+                    attributes.Capacity = (int) entries.GetLength();
                     foreach (var entry in entries)
                     {
                         var key = entry.Get("0");

+ 1 - 1
Jint/Runtime/Modules/ModuleNamespace.cs

@@ -40,7 +40,7 @@ internal sealed class ModuleNamespace : ObjectInstance
     /// <summary>
     /// https://tc39.es/ecma262/#sec-module-namespace-exotic-objects-setprototypeof-v
     /// </summary>
-    public override bool SetPrototypeOf(JsValue value) => SetImmutablePrototype(value);
+    internal override bool SetPrototypeOf(JsValue value) => SetImmutablePrototype(value);
 
     /// <summary>
     /// https://tc39.es/ecma262/#sec-set-immutable-prototype