瀏覽代碼

Fix issues uncovered by latest test262 suite (#1040)

Marko Lahma 3 年之前
父節點
當前提交
4a80efda6a

+ 0 - 72
Jint.Tests.Test262/test/built-ins/Reflect/ownKeys/return-on-corresponding-order-large-index.js

@@ -1,72 +0,0 @@
-// Copyright (C) 2018 the V8 project authors. All rights reserved.
-// This code is governed by the BSD license found in the LICENSE file.
-/*---
-esid: sec-ordinaryownpropertykeys
-description: >
-  Returns keys in their corresponding order.
-info: |
-  26.1.11 Reflect.ownKeys ( target )
-
-  ...
-  2. Let keys be target.[[OwnPropertyKeys]]().
-  3. ReturnIfAbrupt(keys).
-  4. Return CreateArrayFromList(keys).
-
-  9.1.12 [[OwnPropertyKeys]] ( )
-
-  1. Let keys be a new empty List.
-  2. For each own property key P of O that is an integer index, in ascending
-  numeric index order
-    a. Add P as the last element of keys.
-  3. For each own property key P of O that is a String but is not an integer
-  index, in property creation order
-    a. Add P as the last element of keys.
-  4. For each own property key P of O that is a Symbol, in property creation
-  order
-    a. Add P as the last element of keys.
-  5. Return keys.
-features: [computed-property-names, Reflect, Symbol]
----*/
-
-var o1 = {
-  12345678900: true,
-  b: true,
-  1: true,
-  a: true,
-  [Number.MAX_SAFE_INTEGER]: true,
-  [Symbol.for('z')]: true,
-  12345678901: true,
-};
-
-var result = Reflect.ownKeys(o1);
-
-assert.sameValue(result.length, 7);
-assert.sameValue(result[0], '1');
-assert.sameValue(result[1], '12345678900');
-assert.sameValue(result[2], '12345678901');
-assert.sameValue(result[3], String(Number.MAX_SAFE_INTEGER));
-assert.sameValue(result[4], 'b');
-assert.sameValue(result[5], 'a');
-assert.sameValue(result[6], Symbol.for('z'));
-
-var o2 = {};
-
-o2[12345678900] = true;
-o2.b = true;
-o2[1] = true;
-o2.a = true;
-o2[Number.MAX_SAFE_INTEGER] = true;
-o2[Symbol.for('z')] = true;
-o2[12345678901] = true;
-
-
-result = Reflect.ownKeys(o2);
-
-assert.sameValue(result.length, 7);
-assert.sameValue(result[0], '1');
-assert.sameValue(result[1], '12345678900');
-assert.sameValue(result[2], '12345678901');
-assert.sameValue(result[3], String(Number.MAX_SAFE_INTEGER));
-assert.sameValue(result[4], 'b');
-assert.sameValue(result[5], 'a');
-assert.sameValue(result[6], Symbol.for('z'));

+ 12 - 2
Jint/EsprimaExtensions.cs

@@ -3,6 +3,7 @@
 using System;
 using System.Collections.Generic;
 using System.Runtime.CompilerServices;
+using Esprima;
 using Esprima.Ast;
 using Jint.Native;
 using Jint.Native.Function;
@@ -17,12 +18,17 @@ namespace Jint
 {
     public static class EsprimaExtensions
     {
-        public static JsValue GetKey(this ClassProperty property, Engine engine) => GetKey(property.Key, engine, property.Computed);
+        public static JsValue GetKey<T>(this T property, Engine engine) where T : ClassProperty => GetKey(property.Key, engine, property.Computed);
 
         public static JsValue GetKey(this Expression expression, Engine engine, bool resolveComputed = false)
         {
             if (expression is Literal literal)
             {
+                if (literal.TokenType == TokenType.NullLiteral)
+                {
+                    return JsValue.Null;
+                }
+
                 return LiteralKeyToString(literal);
             }
 
@@ -49,7 +55,11 @@ namespace Jint
                 or Nodes.UpdateExpression
                 or Nodes.AssignmentExpression
                 or Nodes.UnaryExpression
-                or Nodes.MemberExpression)
+                or Nodes.MemberExpression
+                or Nodes.LogicalExpression
+                or Nodes.ConditionalExpression
+                or Nodes.ArrowFunctionExpression
+                or Nodes.FunctionExpression)
             {
                 var context = engine._activeEvaluationContext;
                 propertyKey = TypeConverter.ToPropertyKey(JintExpression.Build(engine, expression).GetValue(context).Value);

+ 9 - 4
Jint/Native/Array/ArrayPrototype.cs

@@ -1281,13 +1281,18 @@ namespace Jint.Native.Array
         {
             var array = TypeConverter.ToObject(_realm, thisObj);
 
-            ICallable func = array.Get("join", array) as ICallable;
-            if (func is null)
+            Func<JsValue, JsValue[], JsValue> func;
+            var joinFunc = array.Get("join") as ICallable;
+            if (joinFunc is not null)
             {
-                func = _realm.Intrinsics.Object.PrototypeObject.Get("toString", array) as ICallable;
+                func = joinFunc.Call;
+            }
+            else
+            {
+                func = _realm.Intrinsics.Object.PrototypeObject.ToObjectString;
             }
 
-            return func.Call(array, Arguments.Empty);
+            return func(array, Arguments.Empty);
         }
 
         private JsValue ReduceRight(JsValue thisObj, JsValue[] arguments)

+ 3 - 0
Jint/Native/Date/DatePrototype.cs

@@ -99,6 +99,9 @@ namespace Jint.Native.Date
             SetSymbols(symbols);
         }
 
+        /// <summary>
+        /// https://tc39.es/ecma262/#sec-date.prototype-@@toprimitive
+        /// </summary>
         private JsValue ToPrimitive(JsValue thisObject, JsValue[] arguments)
         {
             var oi = thisObject as ObjectInstance;

+ 8 - 5
Jint/Native/Function/FunctionPrototype.cs

@@ -20,7 +20,7 @@ namespace Jint.Native.Function
             : base(engine, realm, JsString.Empty)
         {
             _prototype = objectPrototype;
-            _length = PropertyDescriptor.AllForbiddenDescriptor.NumberZero;
+            _length = new PropertyDescriptor(JsNumber.PositiveZero, PropertyFlag.Configurable);
         }
 
         protected override void Initialize()
@@ -33,7 +33,7 @@ namespace Jint.Native.Function
                 ["toString"] = new PropertyDescriptor(new ClrFunctionInstance(Engine, "toString", ToString, 0, lengthFlags), propertyFlags),
                 ["apply"] = new PropertyDescriptor(new ClrFunctionInstance(Engine, "apply", Apply, 2, lengthFlags), propertyFlags),
                 ["call"] = new PropertyDescriptor(new ClrFunctionInstance(Engine, "call", CallImpl, 1, lengthFlags), propertyFlags),
-                ["bind"] = new PropertyDescriptor(new ClrFunctionInstance(Engine, "bind", Bind, 1, PropertyFlag.AllForbidden), propertyFlags),
+                ["bind"] = new PropertyDescriptor(new ClrFunctionInstance(Engine, "bind", Bind, 1, lengthFlags), propertyFlags),
                 ["arguments"] = _engine._callerCalleeArgumentsThrowerConfigurable,
                 ["caller"] = _engine._callerCalleeArgumentsThrowerConfigurable
             };
@@ -143,19 +143,22 @@ namespace Jint.Native.Function
                 return func.Call(thisArg, Arguments.Empty);
             }
 
-            var argList = CreateListFromArrayLike(argArray);
+            var argList = CreateListFromArrayLike(_realm, argArray);
 
             var result = func.Call(thisArg, argList);
 
             return result;
         }
 
-        internal JsValue[] CreateListFromArrayLike(JsValue argArray, Types? elementTypes = null)
+        /// <summary>
+        /// https://tc39.es/ecma262/#sec-createlistfromarraylike
+        /// </summary>
+        internal static JsValue[] CreateListFromArrayLike(Realm realm, JsValue argArray, Types? elementTypes = null)
         {
             var argArrayObj = argArray as ObjectInstance;
             if (argArrayObj is null)
             {
-                ExceptionHelper.ThrowTypeError(_realm);
+                ExceptionHelper.ThrowTypeError(realm);
             }
             var operations = ArrayOperations.For(argArrayObj);
             var allowedTypes = elementTypes ??

+ 2 - 2
Jint/Native/Json/JsonInstance.cs

@@ -27,8 +27,8 @@ namespace Jint.Native.Json
             var properties = new PropertyDictionary(2, checkExistingKeys: false)
             {
 #pragma warning disable 618
-                ["parse"] = new PropertyDescriptor(new ClrFunctionInstance(Engine, "parse", Parse, 2), true, false, true),
-                ["stringify"] = new PropertyDescriptor(new ClrFunctionInstance(Engine, "stringify", Stringify, 3), true, false, true)
+                ["parse"] = new PropertyDescriptor(new ClrFunctionInstance(Engine, "parse", Parse, 2, PropertyFlag.Configurable), true, false, true),
+                ["stringify"] = new PropertyDescriptor(new ClrFunctionInstance(Engine, "stringify", Stringify, 3, PropertyFlag.Configurable), true, false, true)
 #pragma warning restore 618
             };
             SetProperties(properties);

+ 4 - 7
Jint/Native/Json/JsonSerializer.cs

@@ -49,14 +49,11 @@ namespace Jint.Native.Json
                 else
                 {
                     var replacerObj = replacer.AsObject();
-                    if (replacerObj.Class == ObjectClass.Array)
-                    {
-                        _propertyList = new List<JsValue>();
-                    }
+                    _propertyList = new List<JsValue>();
 
-                    foreach (var property in replacerObj.GetOwnProperties().Select(x => x.Value))
+                    foreach (var pair in replacerObj.GetOwnProperties())
                     {
-                        JsValue v = _engine.GetValue(property, false);
+                        var v = replacerObj.UnwrapJsValue(pair.Value);
                         string item = null;
                         if (v.IsString())
                         {
@@ -330,7 +327,7 @@ namespace Jint.Native.Json
             _indent += _gap;
 
             var k = _propertyList ?? value.GetOwnProperties()
-                .Where(x => x.Value.Enumerable)
+                .Where(x => !x.Key.IsSymbol() && x.Value.Enumerable)
                 .Select(x => x.Key);
 
             var partial = new List<string>();

+ 2 - 5
Jint/Native/Object/ObjectConstructor.cs

@@ -117,11 +117,8 @@ namespace Jint.Native.Object
         public ObjectPrototype PrototypeObject { get; private set; }
 
         /// <summary>
-        /// http://www.ecma-international.org/ecma-262/5.1/#sec-15.2.1.1
+        /// https://tc39.es/ecma262/#sec-object-value
         /// </summary>
-        /// <param name="thisObject"></param>
-        /// <param name="arguments"></param>
-        /// <returns></returns>
         public override JsValue Call(JsValue thisObject, JsValue[] arguments)
         {
             if (arguments.Length == 0)
@@ -138,7 +135,7 @@ namespace Jint.Native.Object
         }
 
         /// <summary>
-        /// http://www.ecma-international.org/ecma-262/5.1/#sec-15.2.2.1
+        /// https://tc39.es/ecma262/#sec-object-value
         /// </summary>
         public ObjectInstance Construct(JsValue[] arguments)
         {

+ 2 - 2
Jint/Native/Object/ObjectInstance.cs

@@ -232,7 +232,7 @@ namespace Jint.Native.Object
             {
                 foreach (var pair in _properties)
                 {
-                    var isArrayIndex = ulong.TryParse(pair.Key, out var index);
+                    var isArrayIndex = ulong.TryParse(pair.Key, out var index) && index < ArrayOperations.MaxArrayLength;
                     if (isArrayIndex)
                     {
                         keys.Add(JsString.Create(index));
@@ -754,7 +754,7 @@ namespace Jint.Native.Object
 
                     if (o is object)
                     {
-                        var flags = current.Flags & ~(PropertyFlag.Writable | PropertyFlag.WritableSet);
+                        var flags = current.Flags & ~(PropertyFlag.Writable | PropertyFlag.WritableSet | PropertyFlag.CustomJsValue);
                         if (current.IsDataDescriptor())
                         {
                             o.SetOwnProperty(property, current = new GetSetPropertyDescriptor(

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

@@ -1,5 +1,5 @@
 using System.Collections.Generic;
-
+using Jint.Native.Function;
 using Jint.Native.Object;
 using Jint.Runtime;
 using Jint.Runtime.Descriptors;
@@ -122,7 +122,7 @@ namespace Jint.Native.Proxy
                 return _target.GetOwnPropertyKeys(types);
             }
 
-            var trapResult = new List<JsValue>(_engine.Realm.Intrinsics.Function.PrototypeObject.CreateListFromArrayLike(result, Types.String | Types.Symbol));
+            var trapResult = new List<JsValue>(FunctionPrototype.CreateListFromArrayLike(_engine.Realm, result, Types.String | Types.Symbol));
 
             if (trapResult.Count != new HashSet<JsValue>(trapResult).Count)
             {

+ 22 - 5
Jint/Native/Reflect/ReflectInstance.cs

@@ -1,5 +1,7 @@
 using Jint.Collections;
+using Jint.Native.Function;
 using Jint.Native.Object;
+using Jint.Native.Symbol;
 using Jint.Runtime;
 using Jint.Runtime.Descriptors;
 using Jint.Runtime.Interop;
@@ -41,15 +43,30 @@ namespace Jint.Native.Reflect
                 ["setPrototypeOf"] = new PropertyDescriptor(new ClrFunctionInstance(Engine, "setPrototypeOf", SetPrototypeOf, 2, PropertyFlag.Configurable), true, false, true),
             };
             SetProperties(properties);
+
+            var symbols = new SymbolDictionary(1)
+            {
+                [GlobalSymbolRegistry.ToStringTag] = new PropertyDescriptor("Reflect", false, false, true)
+            };
+            SetSymbols(symbols);
         }
 
         private JsValue Apply(JsValue thisObject, JsValue[] arguments)
         {
-            return _realm.Intrinsics.Function.PrototypeObject.Apply(arguments.At(0), new[]
+            var target = arguments.At(0);
+            var thisArgument = arguments.At(1);
+            var argumentsList = arguments.At(2);
+
+            if (!target.IsCallable)
             {
-                arguments.At(1),
-                arguments.At(2)
-            });
+                ExceptionHelper.ThrowTypeError(_realm);
+            }
+
+            var args = FunctionPrototype.CreateListFromArrayLike(_realm, argumentsList);
+
+            // 3. Perform PrepareForTailCall().
+
+            return target.AsCallable().Call(thisArgument, args);
         }
 
         private JsValue Construct(JsValue thisObject, JsValue[] arguments)
@@ -60,7 +77,7 @@ namespace Jint.Native.Reflect
             var newTargetArgument = arguments.At(2, arguments[0]);
             AssertConstructor(_engine, newTargetArgument);
 
-            var args = _realm.Intrinsics.Function.PrototypeObject.CreateListFromArrayLike(arguments.At(1));
+            var args = FunctionPrototype.CreateListFromArrayLike(_realm, arguments.At(1));
 
             return target.Construct(args, newTargetArgument);
         }

+ 6 - 7
Jint/Native/String/StringInstance.cs

@@ -67,14 +67,14 @@ namespace Jint.Native.String
 
         public override IEnumerable<KeyValuePair<JsValue, PropertyDescriptor>> GetOwnProperties()
         {
-            if (_length != null)
+            foreach (var entry in base.GetOwnProperties())
             {
-                yield return new KeyValuePair<JsValue, PropertyDescriptor>(CommonProperties.Length, _length);
+                yield return entry;
             }
 
-            foreach (var entry in base.GetOwnProperties())
+            if (_length != null)
             {
-                yield return entry;
+                yield return new KeyValuePair<JsValue, PropertyDescriptor>(CommonProperties.Length, _length);
             }
         }
 
@@ -86,9 +86,8 @@ namespace Jint.Native.String
                 keys.Add(JsString.Create(i));
             }
 
-            keys.AddRange(base.GetOwnPropertyKeys(types));
-            keys.Sort((v1, v2) => TypeConverter.ToNumber(v1).CompareTo(TypeConverter.ToNumber(v2)));
-
+            keys.AddRange(base.GetOwnPropertyKeys(Types.String));
+            keys.AddRange(base.GetOwnPropertyKeys(Types.Symbol));
             keys.Add(JsString.LengthString);
 
             return keys;