Pārlūkot izejas kodu

Implement some missing Object functionality (#713)

Marko Lahma 5 gadi atpakaļ
vecāks
revīzija
6dc9d457ef
47 mainītis faili ar 782 papildinājumiem un 443 dzēšanām
  1. 104 104
      Jint.Tests.Ecma/TestCases/alltests.json
  2. 15 0
      Jint.Tests.Test262/ObjectTests.cs
  3. 2 4
      Jint.Tests.Test262/Test262Test.cs
  4. 190 0
      Jint.Tests.Test262/test/skipped.json
  5. 0 26
      Jint/ArrayExt.cs
  6. 8 8
      Jint/Engine.cs
  7. 6 21
      Jint/Native/Array/ArrayConstructor.cs
  8. 2 2
      Jint/Native/Array/ArrayInstance.cs
  9. 2 2
      Jint/Native/Array/ArrayPrototype.cs
  10. 1 1
      Jint/Native/Boolean/BooleanConstructor.cs
  11. 3 3
      Jint/Native/Date/DatePrototype.cs
  12. 5 0
      Jint/Native/Error/ErrorConstructor.cs
  13. 1 1
      Jint/Native/Error/ErrorPrototype.cs
  14. 1 1
      Jint/Native/Function/BindFunctionInstance.cs
  15. 1 1
      Jint/Native/Function/FunctionConstructor.cs
  16. 1 1
      Jint/Native/Function/FunctionInstance.cs
  17. 2 5
      Jint/Native/Function/FunctionPrototype.cs
  18. 1 1
      Jint/Native/Function/ThrowTypeError.cs
  19. 2 2
      Jint/Native/Global/GlobalObject.cs
  20. 4 2
      Jint/Native/Iterator/IteratorInstance.cs
  21. 58 0
      Jint/Native/Iterator/IteratorProtocol.cs
  22. 1 0
      Jint/Native/JsString.cs
  23. 9 11
      Jint/Native/JsValue.cs
  24. 2 2
      Jint/Native/Json/JsonSerializer.cs
  25. 4 41
      Jint/Native/Map/MapConstructor.cs
  26. 1 1
      Jint/Native/Number/NumberConstructor.cs
  27. 164 105
      Jint/Native/Object/ObjectConstructor.cs
  28. 66 11
      Jint/Native/Object/ObjectInstance.cs
  29. 19 13
      Jint/Native/Object/ObjectPrototype.cs
  30. 2 3
      Jint/Native/Proxy/ProxyConstructor.cs
  31. 5 7
      Jint/Native/Proxy/ProxyInstance.cs
  32. 12 2
      Jint/Native/Reflect/ReflectInstance.cs
  33. 1 1
      Jint/Native/String/StringConstructor.cs
  34. 16 0
      Jint/Native/String/StringInstance.cs
  35. 1 1
      Jint/Native/String/StringPrototype.cs
  36. 2 3
      Jint/Pooling/JsValueArrayPool.cs
  37. 2 2
      Jint/Runtime/Arguments.cs
  38. 6 6
      Jint/Runtime/Environments/DeclarativeEnvironmentRecord.cs
  39. 2 3
      Jint/Runtime/Environments/ObjectEnvironmentRecord.cs
  40. 2 2
      Jint/Runtime/Interop/DefaultTypeConverter.cs
  41. 3 2
      Jint/Runtime/Interpreter/Expressions/BindingPatternAssignmentExpression.cs
  42. 1 1
      Jint/Runtime/Interpreter/Expressions/JintBinaryExpression.cs
  43. 2 3
      Jint/Runtime/Interpreter/Expressions/JintCallExpression.cs
  44. 41 18
      Jint/Runtime/Interpreter/Expressions/JintObjectExpression.cs
  45. 1 1
      Jint/Runtime/RefStack.cs
  46. 7 18
      Jint/Runtime/TypeConverter.cs
  47. 1 1
      README.md

+ 104 - 104
Jint.Tests.Ecma/TestCases/alltests.json

@@ -22790,28 +22790,28 @@
     source: "ch15/15.2/15.2.3/15.2.3.10/15.2.3.10-0-2.js"
   },
   {
-    skip: false,
-    reason: "",
+    skip: true,
+    reason: "spec has changed",
     source: "ch15/15.2/15.2.3/15.2.3.10/15.2.3.10-1-1.js"
   },
   {
-    skip: false,
-    reason: "",
+    skip: true,
+    reason: "spec has changed",
     source: "ch15/15.2/15.2.3/15.2.3.10/15.2.3.10-1-2.js"
   },
   {
-    skip: false,
-    reason: "",
+    skip: true,
+    reason: "spec has changed",
     source: "ch15/15.2/15.2.3/15.2.3.10/15.2.3.10-1-3.js"
   },
   {
-    skip: false,
-    reason: "",
+    skip: true,
+    reason: "spec has changed",
     source: "ch15/15.2/15.2.3/15.2.3.10/15.2.3.10-1-4.js"
   },
   {
-    skip: false,
-    reason: "",
+    skip: true,
+    reason: "spec has changed",
     source: "ch15/15.2/15.2.3/15.2.3.10/15.2.3.10-1.js"
   },
   {
@@ -22960,8 +22960,8 @@
     source: "ch15/15.2/15.2.3/15.2.3.11/15.2.3.11-0-2.js"
   },
   {
-    skip: false,
-    reason: "",
+    skip: true,
+    reason: "spec has changed",
     source: "ch15/15.2/15.2.3/15.2.3.11/15.2.3.11-1.js"
   },
   {
@@ -23110,23 +23110,23 @@
     source: "ch15/15.2/15.2.3/15.2.3.12/15.2.3.12-0-2.js"
   },
   {
-    skip: false,
-    reason: "",
+    skip: true,
+    reason: "spec has changed",
     source: "ch15/15.2/15.2.3/15.2.3.12/15.2.3.12-1-1.js"
   },
   {
-    skip: false,
-    reason: "",
+    skip: true,
+    reason: "spec has changed",
     source: "ch15/15.2/15.2.3/15.2.3.12/15.2.3.12-1-2.js"
   },
   {
-    skip: false,
-    reason: "",
+    skip: true,
+    reason: "spec has changed",
     source: "ch15/15.2/15.2.3/15.2.3.12/15.2.3.12-1-3.js"
   },
   {
-    skip: false,
-    reason: "",
+    skip: true,
+    reason: "spec has changed",
     source: "ch15/15.2/15.2.3/15.2.3.12/15.2.3.12-1-4.js"
   },
   {
@@ -23145,8 +23145,8 @@
     source: "ch15/15.2/15.2.3/15.2.3.12/15.2.3.12-1-7.js"
   },
   {
-    skip: false,
-    reason: "",
+    skip: true,
+    reason: "spec has changed",
     source: "ch15/15.2/15.2.3/15.2.3.12/15.2.3.12-1.js"
   },
   {
@@ -23395,28 +23395,28 @@
     source: "ch15/15.2/15.2.3/15.2.3.13/15.2.3.13-0-3.js"
   },
   {
-    skip: false,
-    reason: "",
+    skip: true,
+    reason: "spec has changed",
     source: "ch15/15.2/15.2.3/15.2.3.13/15.2.3.13-1-1.js"
   },
   {
-    skip: false,
-    reason: "",
+    skip: true,
+    reason: "spec has changed",
     source: "ch15/15.2/15.2.3/15.2.3.13/15.2.3.13-1-2.js"
   },
   {
-    skip: false,
-    reason: "",
+    skip: true,
+    reason: "spec has changed",
     source: "ch15/15.2/15.2.3/15.2.3.13/15.2.3.13-1-3.js"
   },
   {
-    skip: false,
-    reason: "",
+    skip: true,
+    reason: "spec has changed",
     source: "ch15/15.2/15.2.3/15.2.3.13/15.2.3.13-1-4.js"
   },
   {
-    skip: false,
-    reason: "",
+    skip: true,
+    reason: "spec has changed",
     source: "ch15/15.2/15.2.3/15.2.3.13/15.2.3.13-1.js"
   },
   {
@@ -23570,18 +23570,18 @@
     source: "ch15/15.2/15.2.3/15.2.3.14/15.2.3.14-0-2.js"
   },
   {
-    skip: false,
-    reason: "",
+    skip: true,
+    reason: "spec has changed",
     source: "ch15/15.2/15.2.3/15.2.3.14/15.2.3.14-1-1.js"
   },
   {
-    skip: false,
-    reason: "",
+    skip: true,
+    reason: "spec has changed",
     source: "ch15/15.2/15.2.3/15.2.3.14/15.2.3.14-1-2.js"
   },
   {
-    skip: false,
-    reason: "",
+    skip: true,
+    reason: "spec has changed",
     source: "ch15/15.2/15.2.3/15.2.3.14/15.2.3.14-1-3.js"
   },
   {
@@ -23860,33 +23860,33 @@
     source: "ch15/15.2/15.2.3/15.2.3.2/15.2.3.2-2-11.js"
   },
   {
-    skip: false,
-    reason: "",
+    skip: true,
+    reason: "spec has changed",
     source: "ch15/15.2/15.2.3/15.2.3.2/15.2.3.2-2-12.js"
   },
   {
-    skip: false,
-    reason: "",
+    skip: true,
+    reason: "spec has changed",
     source: "ch15/15.2/15.2.3/15.2.3.2/15.2.3.2-2-13.js"
   },
   {
-    skip: false,
-    reason: "",
+    skip: true,
+    reason: "spec has changed",
     source: "ch15/15.2/15.2.3/15.2.3.2/15.2.3.2-2-14.js"
   },
   {
-    skip: false,
-    reason: "",
+    skip: true,
+    reason: "spec has changed",
     source: "ch15/15.2/15.2.3/15.2.3.2/15.2.3.2-2-15.js"
   },
   {
-    skip: false,
-    reason: "",
+    skip: true,
+    reason: "spec has changed",
     source: "ch15/15.2/15.2.3/15.2.3.2/15.2.3.2-2-16.js"
   },
   {
-    skip: false,
-    reason: "",
+    skip: true,
+    reason: "spec has changed",
     source: "ch15/15.2/15.2.3/15.2.3.2/15.2.3.2-2-17.js"
   },
   {
@@ -24015,18 +24015,18 @@
     source: "ch15/15.2/15.2.3/15.2.3.3/15.2.3.3-1-2.js"
   },
   {
-    skip: false,
-    reason: "",
+    skip: true,
+    reason: "spec has changed",
     source: "ch15/15.2/15.2.3/15.2.3.3/15.2.3.3-1-3.js"
   },
   {
-    skip: false,
-    reason: "",
+    skip: true,
+    reason: "spec has changed",
     source: "ch15/15.2/15.2.3/15.2.3.3/15.2.3.3-1-4.js"
   },
   {
-    skip: false,
-    reason: "",
+    skip: true,
+    reason: "spec has changed",
     source: "ch15/15.2/15.2.3/15.2.3.3/15.2.3.3-1.js"
   },
   {
@@ -24775,8 +24775,8 @@
     source: "ch15/15.2/15.2.3/15.2.3.3/15.2.3.3-4-185.js"
   },
   {
-    skip: false,
-    reason: "",
+    skip: true,
+    reason: "spec has changed",
     source: "ch15/15.2/15.2.3/15.2.3.3/15.2.3.3-4-186.js"
   },
   {
@@ -24805,8 +24805,8 @@
     source: "ch15/15.2/15.2.3/15.2.3.3/15.2.3.3-4-190.js"
   },
   {
-    skip: false,
-    reason: "",
+    skip: true,
+    reason: "spec has changed",
     source: "ch15/15.2/15.2.3/15.2.3.3/15.2.3.3-4-191.js"
   },
   {
@@ -24820,8 +24820,8 @@
     source: "ch15/15.2/15.2.3/15.2.3.3/15.2.3.3-4-193.js"
   },
   {
-    skip: false,
-    reason: "",
+    skip: true,
+    reason: "spec has changed",
     source: "ch15/15.2/15.2.3/15.2.3.3/15.2.3.3-4-194.js"
   },
   {
@@ -24865,8 +24865,8 @@
     source: "ch15/15.2/15.2.3/15.2.3.3/15.2.3.3-4-200.js"
   },
   {
-    skip: false,
-    reason: "",
+    skip: true,
+    reason: "spec has changed",
     source: "ch15/15.2/15.2.3/15.2.3.3/15.2.3.3-4-201.js"
   },
   {
@@ -25545,18 +25545,18 @@
     source: "ch15/15.2/15.2.3/15.2.3.4/15.2.3.4-1-3.js"
   },
   {
-    skip: false,
-    reason: "",
+    skip: true,
+    reason: "spec has changed",
     source: "ch15/15.2/15.2.3/15.2.3.4/15.2.3.4-1-4.js"
   },
   {
-    skip: false,
-    reason: "",
+    skip: true,
+    reason: "spec has changed",
     source: "ch15/15.2/15.2.3/15.2.3.4/15.2.3.4-1-5.js"
   },
   {
-    skip: false,
-    reason: "",
+    skip: true,
+    reason: "spec has changed",
     source: "ch15/15.2/15.2.3/15.2.3.4/15.2.3.4-1.js"
   },
   {
@@ -35965,28 +35965,28 @@
     source: "ch15/15.2/15.2.3/15.2.3.8/15.2.3.8-0-2.js"
   },
   {
-    skip: false,
-    reason: "",
+    skip: true,
+    reason: "spec has changed",
     source: "ch15/15.2/15.2.3/15.2.3.8/15.2.3.8-1-1.js"
   },
   {
-    skip: false,
-    reason: "",
+    skip: true,
+    reason: "spec has changed",
     source: "ch15/15.2/15.2.3/15.2.3.8/15.2.3.8-1-2.js"
   },
   {
-    skip: false,
-    reason: "",
+    skip: true,
+    reason: "spec has changed",
     source: "ch15/15.2/15.2.3/15.2.3.8/15.2.3.8-1-3.js"
   },
   {
-    skip: false,
-    reason: "",
+    skip: true,
+    reason: "spec has changed",
     source: "ch15/15.2/15.2.3/15.2.3.8/15.2.3.8-1-4.js"
   },
   {
-    skip: false,
-    reason: "",
+    skip: true,
+    reason: "spec has changed",
     source: "ch15/15.2/15.2.3/15.2.3.8/15.2.3.8-1.js"
   },
   {
@@ -36180,28 +36180,28 @@
     source: "ch15/15.2/15.2.3/15.2.3.9/15.2.3.9-0-2.js"
   },
   {
-    skip: false,
-    reason: "",
+    skip: true,
+    reason: "spec has changed",
     source: "ch15/15.2/15.2.3/15.2.3.9/15.2.3.9-1-1.js"
   },
   {
-    skip: false,
-    reason: "",
+    skip: true,
+    reason: "spec has changed",
     source: "ch15/15.2/15.2.3/15.2.3.9/15.2.3.9-1-2.js"
   },
   {
-    skip: false,
-    reason: "",
+    skip: true,
+    reason: "spec has changed",
     source: "ch15/15.2/15.2.3/15.2.3.9/15.2.3.9-1-3.js"
   },
   {
-    skip: false,
-    reason: "",
+    skip: true,
+    reason: "spec has changed",
     source: "ch15/15.2/15.2.3/15.2.3.9/15.2.3.9-1-4.js"
   },
   {
-    skip: false,
-    reason: "",
+    skip: true,
+    reason: "spec has changed",
     source: "ch15/15.2/15.2.3/15.2.3.9/15.2.3.9-1.js"
   },
   {
@@ -36500,8 +36500,8 @@
     source: "ch15/15.2/15.2.4/15.2.4.2/S15.2.4.2_A8.js"
   },
   {
-    skip: false,
-    reason: "",
+    skip: true,
+    reason: "spec has changed",
     source: "ch15/15.2/15.2.4/15.2.4.2/S15.2.4.2_A9.js"
   },
   {
@@ -36545,8 +36545,8 @@
     source: "ch15/15.2/15.2.4/15.2.4.3/S15.2.4.3_A8.js"
   },
   {
-    skip: false,
-    reason: "",
+    skip: true,
+    reason: "spec has changed",
     source: "ch15/15.2/15.2.4/15.2.4.3/S15.2.4.3_A9.js"
   },
   {
@@ -36640,8 +36640,8 @@
     source: "ch15/15.2/15.2.4/15.2.4.4/S15.2.4.4_A8.js"
   },
   {
-    skip: false,
-    reason: "",
+    skip: true,
+    reason: "spec has changed",
     source: "ch15/15.2/15.2.4/15.2.4.4/S15.2.4.4_A9.js"
   },
   {
@@ -36695,8 +36695,8 @@
     source: "ch15/15.2/15.2.4/15.2.4.5/S15.2.4.5_A8.js"
   },
   {
-    skip: false,
-    reason: "",
+    skip: true,
+    reason: "spec has changed",
     source: "ch15/15.2/15.2.4/15.2.4.5/S15.2.4.5_A9.js"
   },
   {
@@ -36740,8 +36740,8 @@
     source: "ch15/15.2/15.2.4/15.2.4.6/S15.2.4.6_A8.js"
   },
   {
-    skip: false,
-    reason: "",
+    skip: true,
+    reason: "spec has changed",
     source: "ch15/15.2/15.2.4/15.2.4.6/S15.2.4.6_A9.js"
   },
   {
@@ -36795,8 +36795,8 @@
     source: "ch15/15.2/15.2.4/15.2.4.7/S15.2.4.7_A8.js"
   },
   {
-    skip: false,
-    reason: "",
+    skip: true,
+    reason: "spec has changed",
     source: "ch15/15.2/15.2.4/15.2.4.7/S15.2.4.7_A9.js"
   },
   {
@@ -37135,8 +37135,8 @@
     source: "ch15/15.3/15.3.3/15.3.3.1/S15.3.3.1_A4.js"
   },
   {
-    skip: false,
-    reason: "",
+    skip: true,
+    reason: "spec has changed",
     source: "ch15/15.3/15.3.3/15.3.3.2/15.3.3.2-1.js"
   },
   {

+ 15 - 0
Jint.Tests.Test262/ObjectTests.cs

@@ -0,0 +1,15 @@
+using Xunit;
+
+namespace Jint.Tests.Test262
+{
+    public class ObjectTests : Test262Test
+    {
+        [Theory(DisplayName = "built-ins\\Object")]
+        [MemberData(nameof(SourceFiles), "built-ins\\Object", false)]
+        [MemberData(nameof(SourceFiles), "built-ins\\Object", true, Skip = "Skipped")]
+        protected void RunTest(SourceFile sourceFile)
+        {
+            RunTestInternal(sourceFile);
+        }
+    }
+}

+ 2 - 4
Jint.Tests.Test262/Test262Test.cs

@@ -41,6 +41,7 @@ namespace Jint.Tests.Test262
             {
                 "sta.js",
                 "assert.js",
+                "arrayContains.js",
                 "propertyHelper.js",
                 "compareArray.js",
                 "decimalToHexString.js",
@@ -48,6 +49,7 @@ namespace Jint.Tests.Test262
                 "dateConstants.js",
                 "assertRelativeDateMs.js",
                 "regExpUtils.js",
+                "nans.js",
                 "compareIterator.js"
             };
 
@@ -193,10 +195,6 @@ namespace Jint.Tests.Test262
                                 skip = true;
                                 reason = "class keyword not implemented";
                                 break;
-                            case "object-spread":
-                                skip = true;
-                                reason = "Object spread not implemented";
-                                break;
                             case "BigInt":
                                 skip = true;
                                 reason = "BigInt not implemented";

+ 190 - 0
Jint.Tests.Test262/test/skipped.json

@@ -181,6 +181,10 @@
     "source": "built-ins/Array/prototype/toLocaleString/primitive_this_value_getter.js",
     "reason": "requires toLocaleString changes"
   },
+  {
+    "source": "built-ins/Object/prototype/toLocaleString/primitive_this_value_getter.js",
+    "reason": "requires toLocaleString changes"
+  },
 
   // experimentals start
 
@@ -426,6 +430,187 @@
     "mode": "strict",
     "reason": "let not implemented"
   },
+  {
+    "source": "language/expressions/call/spread-obj-override-immutable.js",
+    "mode": "strict",
+    "reason": "let not implemented"
+  },
+  {
+    "source": "language/expressions/call/spread-obj-overrides-prev-properties.js",
+    "mode": "strict",
+    "reason": "let not implemented"
+  },
+  {
+    "source": "language/expressions/call/spread-obj-skip-non-enumerable.js",
+    "mode": "strict",
+    "reason": "let not implemented"
+  },
+  {
+    "source": "language/expressions/call/spread-obj-with-overrides.js",
+    "mode": "strict",
+    "reason": "let not implemented"
+  },
+  {
+    "source": "language/expressions/call/spread-sngl-obj-ident.js",
+    "mode": "strict",
+    "reason": "let not implemented"
+  },
+  {
+    "source": "language/expressions/call/spread-obj-mult-spread.js",
+    "mode": "strict",
+    "reason": "let not implemented"
+  },
+  {
+    "source": "language/expressions/call/spread-obj-getter-descriptor.js",
+    "mode": "strict",
+    "reason": "let not implemented"
+  },
+  {
+    "source": "language/expressions/call/spread-obj-mult-spread-getter.js",
+    "mode": "strict",
+    "reason": "let not implemented"
+  },
+  {
+    "source": "language/expressions/call/spread-obj-getter-init.js",
+    "mode": "strict",
+    "reason": "let not implemented"
+  },
+  {
+    "source": "language/expressions/call/spread-mult-obj-ident.js",
+    "mode": "strict",
+    "reason": "let not implemented"
+  },
+  {
+    "source": "language/expressions/new/spread-mult-obj-ident.js",
+    "mode": "strict",
+    "reason": "let not implemented"
+  },
+  {
+    "source": "language/expressions/new/spread-obj-getter-descriptor.js",
+    "mode": "strict",
+    "reason": "let not implemented"
+  },
+  {
+    "source": "language/expressions/new/spread-obj-getter-init.js",
+    "mode": "strict",
+    "reason": "let not implemented"
+  },
+  {
+    "source": "language/expressions/new/spread-obj-mult-spread-getter.js",
+    "mode": "strict",
+    "reason": "let not implemented"
+  },
+  {
+    "source": "language/expressions/new/spread-obj-mult-spread.js",
+    "mode": "strict",
+    "reason": "let not implemented"
+  },
+  {
+    "source": "language/expressions/new/spread-obj-override-immutable.js",
+    "mode": "strict",
+    "reason": "let not implemented"
+  },
+  {
+    "source": "language/expressions/new/spread-obj-overrides-prev-properties.js",
+    "mode": "strict",
+    "reason": "let not implemented"
+  },
+  {
+    "source": "language/expressions/new/spread-obj-skip-non-enumerable.js",
+    "mode": "strict",
+    "reason": "let not implemented"
+  },
+  {
+    "source": "language/expressions/new/spread-obj-with-overrides.js",
+    "mode": "strict",
+    "reason": "let not implemented"
+  },
+  {
+    "source": "language/expressions/new/spread-sngl-obj-ident.js",
+    "mode": "strict",
+    "reason": "let not implemented"
+  },
+  {
+    "source": "language/expressions/array/spread-mult-obj-ident.js",
+    "mode": "strict",
+    "reason": "let not implemented"
+  },
+  {
+    "source": "language/expressions/array/spread-obj-getter-descriptor.js",
+    "mode": "strict",
+    "reason": "let not implemented"
+  },
+  {
+    "source": "language/expressions/array/spread-obj-getter-init.js",
+    "mode": "strict",
+    "reason": "let not implemented"
+  },
+  {
+    "source": "language/expressions/array/spread-obj-mult-spread-getter.js",
+    "mode": "strict",
+    "reason": "let not implemented"
+  },
+  {
+    "source": "language/expressions/array/spread-obj-mult-spread.js",
+    "mode": "strict",
+    "reason": "let not implemented"
+  },
+  {
+    "source": "language/expressions/array/spread-obj-override-immutable.js",
+    "mode": "strict",
+    "reason": "let not implemented"
+  },
+  {
+    "source": "language/expressions/array/spread-obj-overrides-prev-properties.js",
+    "mode": "strict",
+    "reason": "let not implemented"
+  },
+  {
+    "source": "language/expressions/array/spread-obj-skip-non-enumerable.js",
+    "mode": "strict",
+    "reason": "let not implemented"
+  },
+  {
+    "source": "language/expressions/array/spread-obj-with-overrides.js",
+    "mode": "strict",
+    "reason": "let not implemented"
+  },
+  {
+    "source": "language/expressions/array/spread-sngl-obj-ident.js",
+    "mode": "strict",
+    "reason": "let not implemented"
+  },
+  {
+    "source": "language/expressions/array/spread-obj-symbol-property.js",
+    "mode": "strict",
+    "reason": "let not implemented"
+  },
+  {
+    "source": "language/expressions/new/spread-obj-symbol-property.js",
+    "mode": "strict",
+    "reason": "let not implemented"
+  },
+  {
+    "source": "language/expressions/call/spread-obj-symbol-property.js",
+    "mode": "strict",
+    "reason": "let not implemented"
+  },
+  {
+    "source": "built-ins/Object/entries/tamper-with-global-object.js",
+    "mode": "strict",
+    "reason": "let not implemented"
+  },
+  {
+    "source": "built-ins/Object/values/tamper-with-global-object.js",
+    "mode": "strict",
+    "reason": "let not implemented"
+  },
+  {
+    "source": "built-ins/Object/keys/proxy-keys.js",
+    "mode": "strict",
+    "reason": "let not implemented"
+  },
+
 
   // class support
   {
@@ -616,6 +801,11 @@
     "reason": "not implemented: Creation of new variable environment for the function body (as distinct from that for the function's parameters)"
   },
 
+  {
+    "source": "built-ins/Object/prototype/toString/proxy-function.js",
+    "reason": "generators not implemented"
+  },
+
   // Esprima problems
 
   {

+ 0 - 26
Jint/ArrayExt.cs

@@ -1,26 +0,0 @@
-
-using System.Runtime.CompilerServices;
-
-namespace System
-{
-    internal static class ArrayExt
-    {
-        private static class EmptyArray<T>
-        {
-            public static readonly T[] Value;
-
-            static EmptyArray()
-            {
-                Value = new T[0];
-            }
-        }
-
-        #if NETSTANDARD
-        [MethodImpl(MethodImplOptions.AggressiveInlining)]
-        public static T[] Empty<T>() => Array.Empty<T>();
-        #else
-        [MethodImpl(MethodImplOptions.AggressiveInlining)]
-        public static T[] Empty<T>() => EmptyArray<T>.Value;
-        #endif
-    }
-}

+ 8 - 8
Jint/Engine.cs

@@ -228,7 +228,7 @@ namespace Jint
             _argumentsInstancePool = new ArgumentsInstancePool(this);
             _jsValueArrayPool = new JsValueArrayPool();
 
-            Eval = new EvalFunctionInstance(this, ArrayExt.Empty<string>(), LexicalEnvironment.NewDeclarativeEnvironment(this, ExecutionContext.LexicalEnvironment), StrictModeScope.IsStrictModeCode);
+            Eval = new EvalFunctionInstance(this, System.Array.Empty<string>(), LexicalEnvironment.NewDeclarativeEnvironment(this, ExecutionContext.LexicalEnvironment), StrictModeScope.IsStrictModeCode);
             Global.SetProperty(CommonProperties.Eval, new PropertyDescriptor(Eval, PropertyFlag.Configurable | PropertyFlag.Writable));
 
             if (Options._IsClrAllowed)
@@ -263,13 +263,13 @@ namespace Jint
         public SymbolConstructor Symbol { get; }
         public EvalFunctionInstance Eval { get; }
 
-        public ErrorConstructor Error => _error ?? (_error = ErrorConstructor.CreateErrorConstructor(this, _errorFunctionName));
-        public ErrorConstructor EvalError => _evalError ?? (_evalError = ErrorConstructor.CreateErrorConstructor(this, _evalErrorFunctionName));
-        public ErrorConstructor SyntaxError => _syntaxError ?? (_syntaxError = ErrorConstructor.CreateErrorConstructor(this, _syntaxErrorFunctionName));
-        public ErrorConstructor TypeError => _typeError ?? (_typeError = ErrorConstructor.CreateErrorConstructor(this, _typeErrorFunctionName));
-        public ErrorConstructor RangeError => _rangeError ?? (_rangeError = ErrorConstructor.CreateErrorConstructor(this, _rangeErrorFunctionName));
-        public ErrorConstructor ReferenceError => _referenceError ?? (_referenceError = ErrorConstructor.CreateErrorConstructor(this, _referenceErrorFunctionName));
-        public ErrorConstructor UriError => _uriError ?? (_uriError = ErrorConstructor.CreateErrorConstructor(this, _uriErrorFunctionName));
+        public ErrorConstructor Error => _error ??= ErrorConstructor.CreateErrorConstructor(this, _errorFunctionName);
+        public ErrorConstructor EvalError => _evalError ??= ErrorConstructor.CreateErrorConstructor(this, _evalErrorFunctionName);
+        public ErrorConstructor SyntaxError => _syntaxError ??= ErrorConstructor.CreateErrorConstructor(this, _syntaxErrorFunctionName);
+        public ErrorConstructor TypeError => _typeError ??= ErrorConstructor.CreateErrorConstructor(this, _typeErrorFunctionName);
+        public ErrorConstructor RangeError => _rangeError ??= ErrorConstructor.CreateErrorConstructor(this, _rangeErrorFunctionName);
+        public ErrorConstructor ReferenceError => _referenceError ??= ErrorConstructor.CreateErrorConstructor(this, _referenceErrorFunctionName);
+        public ErrorConstructor UriError => _uriError ??= ErrorConstructor.CreateErrorConstructor(this, _uriErrorFunctionName);
 
         public ref readonly ExecutionContext ExecutionContext
         {

+ 6 - 21
Jint/Native/Array/ArrayConstructor.cs

@@ -1,12 +1,10 @@
-using System;
-using System.Collections;
+using System.Collections;
 using System.Collections.Generic;
 using System.Runtime.CompilerServices;
 using Jint.Collections;
 using Jint.Native.Function;
 using Jint.Native.Iterator;
 using Jint.Native.Object;
-using Jint.Native.Proxy;
 using Jint.Native.Symbol;
 using Jint.Runtime;
 using Jint.Runtime.Descriptors;
@@ -100,7 +98,7 @@ namespace Jint.Native.Array
             ObjectInstance instance;
             if (thisObj is IConstructor constructor)
             {
-                instance = constructor.Construct(ArrayExt.Empty<JsValue>(), thisObj);
+                instance = constructor.Construct(System.Array.Empty<JsValue>(), thisObj);
             }
             else
             {
@@ -269,25 +267,12 @@ namespace Jint.Native.Array
 
         private static JsValue IsArray(JsValue o)
         {
-            if (!o.IsObject())
+            if (!(o is ObjectInstance oi))
             {
                 return JsBoolean.False;
             }
 
-            var objectClass = o.AsObject().Class;
-            if (objectClass == ObjectClass.Array)
-            {
-                return JsBoolean.True;
-            }
-
-            if (objectClass == ObjectClass.Proxy)
-            {
-                var proxyInstance = (ProxyInstance) o;
-                proxyInstance.AssertNotRevoked("isArray");
-                return IsArray(proxyInstance._target);
-            }
-
-            return JsBoolean.False;
+            return oi.IsArray();
         }
 
         public override JsValue Call(JsValue thisObject, JsValue[] arguments)
@@ -315,12 +300,12 @@ namespace Jint.Native.Array
 
         public ArrayInstance Construct(int capacity)
         {
-            return Construct(System.ArrayExt.Empty<JsValue>(), (uint) capacity);
+            return Construct(System.Array.Empty<JsValue>(), (uint) capacity);
         }
 
         public ArrayInstance Construct(uint capacity)
         {
-            return Construct(System.ArrayExt.Empty<JsValue>(), capacity);
+            return Construct(System.Array.Empty<JsValue>(), capacity);
         }
 
         public ArrayInstance Construct(JsValue[] arguments, uint capacity)

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

@@ -22,7 +22,7 @@ namespace Jint.Native.Array
         {
             if (capacity < MaxDenseArrayLength)
             {
-                _dense = capacity > 0 ? new PropertyDescriptor[capacity] : System.ArrayExt.Empty<PropertyDescriptor>();
+                _dense = capacity > 0 ? new PropertyDescriptor[capacity] : System.Array.Empty<PropertyDescriptor>();
             }
             else
             {
@@ -38,7 +38,7 @@ namespace Jint.Native.Array
             int length = 0;
             if (items == null || items.Length == 0)
             {
-                _dense = System.ArrayExt.Empty<PropertyDescriptor>();
+                _dense = System.Array.Empty<PropertyDescriptor>();
                 length = 0;
             }
             else

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

@@ -643,7 +643,7 @@ namespace Jint.Native.Array
                 actualStart = (ulong) System.Math.Min(relativeStart, len);
             }
 
-            var items = ArrayExt.Empty<JsValue>();
+            var items = System.Array.Empty<JsValue>();
             ulong insertCount;
             ulong actualDeleteCount;
             if (arguments.Length == 0)
@@ -662,7 +662,7 @@ namespace Jint.Native.Array
                 var dc = TypeConverter.ToInteger(deleteCount);
                 actualDeleteCount = (ulong) System.Math.Min(System.Math.Max(dc,0), len - actualStart);
 
-                items = ArrayExt.Empty<JsValue>();
+                items = System.Array.Empty<JsValue>();
                 if (arguments.Length > 2)
                 {
                     items = new JsValue[arguments.Length - 2];

+ 1 - 1
Jint/Native/Boolean/BooleanConstructor.cs

@@ -22,7 +22,7 @@ namespace Jint.Native.Boolean
             obj._prototype = engine.Function.PrototypeObject;
             obj.PrototypeObject = BooleanPrototype.CreatePrototypeObject(engine, obj);
 
-            obj._length = PropertyDescriptor.AllForbiddenDescriptor.NumberOne;
+            obj._length = new PropertyDescriptor(JsNumber.One, PropertyFlag.Configurable);
 
             // The initial value of Boolean.prototype is the Boolean prototype object
             obj._prototypeDescriptor = new PropertyDescriptor(obj.PrototypeObject, PropertyFlag.AllForbidden);

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

@@ -694,12 +694,12 @@ namespace Jint.Native.Date
             }
 
             var toIso = o.Get("toISOString", o);
-            if (!toIso.Is<ICallable>())
+            if (!(toIso is ICallable callable))
             {
-                ExceptionHelper.ThrowTypeError(Engine);
+                return ExceptionHelper.ThrowTypeError<JsValue>(Engine);
             }
 
-            return toIso.TryCast<ICallable>().Call(o, Arguments.Empty);
+            return callable.Call(o, Arguments.Empty);
         }
 
         public const int HoursPerDay = 24;

+ 5 - 0
Jint/Native/Error/ErrorConstructor.cs

@@ -60,5 +60,10 @@ namespace Jint.Native.Error
         }
 
         public ErrorPrototype PrototypeObject { get; private set; }
+
+        protected override ObjectInstance GetPrototypeOf()
+        {
+            return _name._value != "Error" ? _engine.Error : _prototype;
+        }
     }
 }

+ 1 - 1
Jint/Native/Error/ErrorPrototype.cs

@@ -25,7 +25,7 @@ namespace Jint.Native.Error
                 _errorConstructor = errorConstructor,
             };
 
-            if (name.ToString() != "Error")
+            if (name._value != "Error")
             {
                 obj._prototype = engine.Error.PrototypeObject;
             }

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

@@ -7,7 +7,7 @@ namespace Jint.Native.Function
     public sealed class BindFunctionInstance : FunctionInstance, IConstructor
     {
         public BindFunctionInstance(Engine engine)
-            : base(engine, "bind", System.ArrayExt.Empty<string>(), null, false)
+            : base(engine, "bind", System.Array.Empty<string>(), null, false)
         {
         }
 

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

@@ -33,7 +33,7 @@ namespace Jint.Native.Function
             obj._prototype = obj.PrototypeObject;
 
             obj._prototypeDescriptor = new PropertyDescriptor(obj.PrototypeObject, PropertyFlag.AllForbidden);
-            obj._length =  PropertyDescriptor.AllForbiddenDescriptor.NumberOne;
+            obj._length = new PropertyDescriptor(JsNumber.One, PropertyFlag.Configurable);
 
             return obj;
         }

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

@@ -167,7 +167,7 @@ namespace Jint.Native.Function
             if (property == CommonProperties.Name)
             {
                 return !(_name is null)
-                    ? _nameDescriptor ?? (_nameDescriptor = new PropertyDescriptor(_name, PropertyFlag.Configurable))
+                    ? _nameDescriptor ??= new PropertyDescriptor(_name, PropertyFlag.Configurable)
                     :  PropertyDescriptor.Undefined;
             }
 

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

@@ -1,5 +1,4 @@
-using System;
-using Jint.Collections;
+using Jint.Collections;
 using Jint.Native.Array;
 using Jint.Native.Object;
 using Jint.Runtime;
@@ -52,8 +51,6 @@ namespace Jint.Native.Function
                 ExceptionHelper.ThrowTypeError(Engine);
             });
 
-            var func = thisObj as IConstructor;
-            
             var thisArg = arguments.At(0);
             var f = new BindFunctionInstance(Engine)
             {
@@ -121,7 +118,7 @@ namespace Jint.Native.Function
         private JsValue CallImpl(JsValue thisObject, JsValue[] arguments)
         {
             var func = thisObject as ICallable ?? ExceptionHelper.ThrowTypeError<ICallable>(Engine);
-            JsValue[] values = ArrayExt.Empty<JsValue>();
+            JsValue[] values = System.Array.Empty<JsValue>();
             if (arguments.Length > 1)
             {
                 values = new JsValue[arguments.Length - 1];

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

@@ -8,7 +8,7 @@ namespace Jint.Native.Function
         private static readonly JsString _functionName = new JsString("throwTypeError");
 
         public ThrowTypeError(Engine engine)
-            : base(engine, _functionName, System.ArrayExt.Empty<string>(), engine.GlobalEnvironment, false)
+            : base(engine, _functionName, System.Array.Empty<string>(), engine.GlobalEnvironment, false)
         {
             _length = PropertyDescriptor.AllForbiddenDescriptor.NumberZero;
             PreventExtensions();

+ 2 - 2
Jint/Native/Global/GlobalObject.cs

@@ -452,7 +452,7 @@ namespace Jint.Native.Global
                         v = (c - 0xD800) * 0x400 + (kChar - 0xDC00) + 0x10000;
                     }
 
-                    byte[] octets = ArrayExt.Empty<byte>();
+                    byte[] octets = System.Array.Empty<byte>();
 
                     if (v >= 0 && v <= 0x007F)
                     {
@@ -536,7 +536,7 @@ namespace Jint.Native.Global
             _stringBuilder.EnsureCapacity(strLen);
             _stringBuilder.Clear();
 
-            var octets = ArrayExt.Empty<byte>();
+            var octets = System.Array.Empty<byte>();
 
             for (var k = 0; k < strLen; k++)
             {

+ 4 - 2
Jint/Native/Iterator/IteratorInstance.cs

@@ -286,12 +286,14 @@ namespace Jint.Native.Iterator
             public ObjectWrapper(ObjectInstance target)
             {
                 _target = target;
-                _callable = (ICallable) target.Get(CommonProperties.Next, target);
+                _callable = target.Get(CommonProperties.Next, target) as ICallable
+                            ?? ExceptionHelper.ThrowTypeError<ICallable>(target.Engine);
             }
 
             public ObjectInstance Next()
             {
-                return (ObjectInstance) _callable.Call(_target, Arguments.Empty);
+                return _callable.Call(_target, Arguments.Empty) as ObjectInstance
+                       ?? ExceptionHelper.ThrowTypeError<ObjectInstance>(_target.Engine);
             }
 
             public void Return()

+ 58 - 0
Jint/Native/Iterator/IteratorProtocol.cs

@@ -1,4 +1,5 @@
 using Jint.Native.Array;
+using Jint.Native.Object;
 using Jint.Runtime;
 
 namespace Jint.Native.Iterator
@@ -85,5 +86,62 @@ namespace Jint.Native.Iterator
 
             return jsValue;
         }
+
+        internal static void AddEntriesFromIterable(ObjectInstance target, IIterator iterable, object adder)
+        {
+            if (!(adder is ICallable callable))
+            {
+                ExceptionHelper.ThrowTypeError(target.Engine, "set must be callable");
+                return;
+            }
+
+            var close = false;
+            var args = target.Engine._jsValueArrayPool.RentArray(2);
+            try
+            {
+                do
+                {
+                    var item = iterable.Next();
+                    if (item.TryGetValue(CommonProperties.Done, out var done) && done.AsBoolean())
+                    {
+                        close = true;
+                        break;
+                    }
+
+                    if (!item.TryGetValue(CommonProperties.Value, out var currentValue))
+                    {
+                        currentValue = JsValue.Undefined;
+                    }
+
+                    close = true;
+                    if (!(currentValue is ObjectInstance oi))
+                    {
+                        ExceptionHelper.ThrowTypeError(target.Engine, "iterator's value must be an object");
+                        return;
+                    }
+
+                    var k = oi.Get(JsString.NumberZeroString);
+                    var v = oi.Get(JsString.NumberOneString);
+
+                    args[0] = k;
+                    args[1] = v;
+
+                    callable.Call(target, args);
+                } while (true);
+            }
+            catch
+            {
+                if (close)
+                {
+                    iterable.Return();
+                }
+                throw;
+            }
+            finally
+            {
+                target.Engine._jsValueArrayPool.ReturnArray(args);
+            }
+        }
+
     }
 }

+ 1 - 0
Jint/Native/JsString.cs

@@ -26,6 +26,7 @@ namespace Jint.Native
         internal static readonly JsString NumberOneString = new JsString("1");
         internal static readonly JsString TrueString = new JsString("true");
         internal static readonly JsString FalseString = new JsString("false");
+        internal static readonly JsString LengthString = new JsString("length");
 
         internal string _value;
 

+ 9 - 11
Jint/Native/JsValue.cs

@@ -249,14 +249,7 @@ namespace Jint.Native
 
             return null;
         }
-
-        [Pure]
-        [MethodImpl(MethodImplOptions.AggressiveInlining)]
-        public bool Is<T>()
-        {
-            return IsObject() && this is T;
-        }
-
+        
         [Pure]
         [MethodImpl(MethodImplOptions.AggressiveInlining)]
         public T As<T>() where T : ObjectInstance
@@ -604,8 +597,8 @@ namespace Jint.Native
 
         internal static bool SameValue(JsValue x, JsValue y)
         {
-            var typea = TypeConverter.GetInternalPrimitiveType(x);
-            var typeb = TypeConverter.GetInternalPrimitiveType(y);
+            var typea = x.Type;
+            var typeb = y.Type;
 
             if (typea != typeb)
             {
@@ -644,8 +637,13 @@ namespace Jint.Native
                     return TypeConverter.ToString(x) == TypeConverter.ToString(y);
                 case Types.Boolean:
                     return TypeConverter.ToBoolean(x) == TypeConverter.ToBoolean(y);
-                default:
+                case Types.Undefined:
+                case Types.Null:
+                    return true;
+                case Types.Symbol:
                     return x == y;
+                default:
+                    return ReferenceEquals(x, y);
             }
         }
     }

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

@@ -28,14 +28,14 @@ namespace Jint.Native.Json
 
             // for JSON.stringify(), any function passed as the first argument will return undefined
             // if the replacer is not defined. The function is not called either.
-            if (value.Is<ICallable>() && ReferenceEquals(replacer, Undefined.Instance))
+            if (value is ICallable callable && ReferenceEquals(replacer, Undefined.Instance))
             {
                 return Undefined.Instance;
             }
 
             if (replacer.IsObject())
             {
-                if (replacer.Is<ICallable>())
+                if (replacer is ICallable)
                 {
                     _replacerFunction = replacer;
                 }

+ 4 - 41
Jint/Native/Map/MapConstructor.cs

@@ -65,57 +65,20 @@ namespace Jint.Native.Map
 
         public ObjectInstance Construct(JsValue[] arguments, JsValue newTarget)
         {
-            var instance = new MapInstance(Engine)
+            var map = new MapInstance(Engine)
             {
                 _prototype = PrototypeObject
             };
 
             if (arguments.Length > 0 && !arguments[0].IsNullOrUndefined())
             {
+                var adder = map.Get("set");
                 var iterator = arguments.At(0).GetIterator(_engine);
-                var mapProtocol = new MapProtocol(_engine, instance, iterator);
-                mapProtocol.Execute();
-            }
-
-            return instance;
-        }
-
-        private sealed class MapProtocol : IteratorProtocol
-        {
-            private readonly MapInstance _instance;
-            private readonly ICallable _setter;
 
-            public MapProtocol(
-                Engine engine,
-                MapInstance instance,
-                IIterator iterator) : base(engine, iterator, 2)
-            {
-                _instance = instance;
-                var setterProperty = instance.GetProperty(CommonProperties.Set);
-
-                if (setterProperty is null
-                    || !setterProperty.TryGetValue(instance, out var setterValue)
-                    || (_setter = setterValue as ICallable) is null)
-                {
-                    ExceptionHelper.ThrowTypeError(_engine, "set must be callable");
-                }
+                IteratorProtocol.AddEntriesFromIterable(map, iterator, adder);
             }
 
-            protected override void ProcessItem(JsValue[] args, JsValue currentValue)
-            {
-                if (!(currentValue is ObjectInstance oi))
-                {
-                    ExceptionHelper.ThrowTypeError(_engine, "iterator's value must be an object");
-                    return;
-                }
-
-                oi.TryGetValue(JsString.NumberZeroString, out var key);
-                oi.TryGetValue(JsString.NumberOneString, out var value);
-
-                args[0] = key;
-                args[1] = value;
-                _setter.Call(_instance, args);
-            }
+            return map;
         }
     }
 }

+ 1 - 1
Jint/Native/Number/NumberConstructor.cs

@@ -31,7 +31,7 @@ namespace Jint.Native.Number
             // The value of the [[Prototype]] internal property of the Number constructor is the Function prototype object
             obj.PrototypeObject = NumberPrototype.CreatePrototypeObject(engine, obj);
 
-            obj._length = new PropertyDescriptor(1, PropertyFlag.AllForbidden);
+            obj._length = new PropertyDescriptor(JsNumber.One, PropertyFlag.Configurable);
 
             // The initial value of Number.prototype is the Number prototype object
             obj._prototypeDescriptor = new PropertyDescriptor(obj.PrototypeObject, PropertyFlag.AllForbidden);

+ 164 - 105
Jint/Native/Object/ObjectConstructor.cs

@@ -1,8 +1,7 @@
 using System.Collections.Generic;
 using Jint.Collections;
-using Jint.Native.Array;
 using Jint.Native.Function;
-using Jint.Native.String;
+using Jint.Native.Iterator;
 using Jint.Runtime;
 using Jint.Runtime.Descriptors;
 using Jint.Runtime.Interop;
@@ -32,27 +31,93 @@ namespace Jint.Native.Object
         {
             _prototype = Engine.Function.PrototypeObject;
 
+            const PropertyFlag propertyFlags = PropertyFlag.Configurable | PropertyFlag.Writable;
+            const PropertyFlag lengthFlags = PropertyFlag.Configurable;
             var properties = new PropertyDictionary(15, checkExistingKeys: false)
             {
-                ["getPrototypeOf"] = new PropertyDescriptor(new ClrFunctionInstance(Engine, "getPrototypeOf", GetPrototypeOf, 1), true, false, true),
-                ["getOwnPropertyDescriptor"] = new PropertyDescriptor(new ClrFunctionInstance(Engine, "getOwnPropertyDescriptor", GetOwnPropertyDescriptor, 2), true, false, true),
-                ["getOwnPropertyNames"] = new PropertyDescriptor(new ClrFunctionInstance(Engine, "getOwnPropertyNames", GetOwnPropertyNames, 1), true, false, true),
-                ["getOwnPropertySymbols"] = new PropertyDescriptor(new ClrFunctionInstance(Engine, "getOwnPropertySymbols", GetOwnPropertySymbols, 1), true, false, true),
-                ["create"] = new PropertyDescriptor(new ClrFunctionInstance(Engine, "create", Create, 2), true, false, true),
-                ["defineProperty"] = new PropertyDescriptor(new ClrFunctionInstance(Engine, "defineProperty", DefineProperty, 3), true, false, true),
-                ["defineProperties"] = new PropertyDescriptor(new ClrFunctionInstance(Engine, "defineProperties", DefineProperties, 2), true, false, true),
-                ["seal"] = new PropertyDescriptor(new ClrFunctionInstance(Engine, "seal", Seal, 1), true, false, true),
-                ["freeze"] = new PropertyDescriptor(new ClrFunctionInstance(Engine, "freeze", Freeze, 1), true, false, true),
-                ["preventExtensions"] = new PropertyDescriptor(new ClrFunctionInstance(Engine, "preventExtensions", PreventExtensions, 1), true, false, true),
-                ["isSealed"] = new PropertyDescriptor(new ClrFunctionInstance(Engine, "isSealed", IsSealed, 1), true, false, true),
-                ["isFrozen"] = new PropertyDescriptor(new ClrFunctionInstance(Engine, "isFrozen", IsFrozen, 1), true, false, true),
-                ["isExtensible"] = new PropertyDescriptor(new ClrFunctionInstance(Engine, "isExtensible", IsExtensible, 1), true, false, true),
-                ["keys"] = new PropertyDescriptor(new ClrFunctionInstance(Engine, "keys", Keys, 1), true, false, true),
-                ["setPrototypeOf"] = new PropertyDescriptor(new ClrFunctionInstance(Engine, "setPrototypeOf", SetPrototypeOf, 2), true, false, true)
+                ["assign"] = new PropertyDescriptor(new ClrFunctionInstance(Engine, "assign", Assign, 2, lengthFlags), propertyFlags),
+                ["entries"] = new PropertyDescriptor(new ClrFunctionInstance(Engine, "entries", Entries, 1, lengthFlags), propertyFlags),
+                ["fromEntries"] = new PropertyDescriptor(new ClrFunctionInstance(Engine, "fromEntries", FromEntries, 1, lengthFlags), propertyFlags),
+                ["getPrototypeOf"] = new PropertyDescriptor(new ClrFunctionInstance(Engine, "getPrototypeOf", GetPrototypeOf, 1), propertyFlags),
+                ["getOwnPropertyDescriptor"] = new PropertyDescriptor(new ClrFunctionInstance(Engine, "getOwnPropertyDescriptor", GetOwnPropertyDescriptor, 2), propertyFlags),
+                ["getOwnPropertyDescriptors"] = new PropertyDescriptor(new ClrFunctionInstance(Engine, "getOwnPropertyDescriptors", GetOwnPropertyDescriptors, 1, lengthFlags), propertyFlags),
+                ["getOwnPropertyNames"] = new PropertyDescriptor(new ClrFunctionInstance(Engine, "getOwnPropertyNames", GetOwnPropertyNames, 1), propertyFlags),
+                ["getOwnPropertySymbols"] = new PropertyDescriptor(new ClrFunctionInstance(Engine, "getOwnPropertySymbols", GetOwnPropertySymbols, 1, lengthFlags), propertyFlags),
+                ["create"] = new PropertyDescriptor(new ClrFunctionInstance(Engine, "create", Create, 2), propertyFlags),
+                ["defineProperty"] = new PropertyDescriptor(new ClrFunctionInstance(Engine, "defineProperty", DefineProperty, 3), propertyFlags),
+                ["defineProperties"] = new PropertyDescriptor(new ClrFunctionInstance(Engine, "defineProperties", DefineProperties, 2), propertyFlags),
+                ["is"] = new PropertyDescriptor(new ClrFunctionInstance(Engine, "is", Is, 2, lengthFlags), propertyFlags),
+                ["seal"] = new PropertyDescriptor(new ClrFunctionInstance(Engine, "seal", Seal, 1), propertyFlags),
+                ["freeze"] = new PropertyDescriptor(new ClrFunctionInstance(Engine, "freeze", Freeze, 1), propertyFlags),
+                ["preventExtensions"] = new PropertyDescriptor(new ClrFunctionInstance(Engine, "preventExtensions", PreventExtensions, 1), propertyFlags),
+                ["isSealed"] = new PropertyDescriptor(new ClrFunctionInstance(Engine, "isSealed", IsSealed, 1), propertyFlags),
+                ["isFrozen"] = new PropertyDescriptor(new ClrFunctionInstance(Engine, "isFrozen", IsFrozen, 1), propertyFlags),
+                ["isExtensible"] = new PropertyDescriptor(new ClrFunctionInstance(Engine, "isExtensible", IsExtensible, 1), propertyFlags),
+                ["keys"] = new PropertyDescriptor(new ClrFunctionInstance(Engine, "keys", Keys, 1, lengthFlags), propertyFlags),
+                ["values"] = new PropertyDescriptor(new ClrFunctionInstance(Engine, "values", Values, 1, lengthFlags), propertyFlags),
+                ["setPrototypeOf"] = new PropertyDescriptor(new ClrFunctionInstance(Engine, "setPrototypeOf", SetPrototypeOf, 2, lengthFlags), propertyFlags)
             };
             SetProperties(properties);
         }
 
+        private JsValue Assign(JsValue thisObject, JsValue[] arguments)
+        {
+            var to = TypeConverter.ToObject(_engine, arguments.At(0));
+            if (arguments.Length < 2)
+            {
+                return to;
+            }
+
+            for (var i = 1; i < arguments.Length; i++)
+            {
+                var nextSource = arguments[i];
+                if (nextSource.IsNullOrUndefined())
+                {
+                    continue;
+                }
+
+                var from = TypeConverter.ToObject(_engine, nextSource);
+                var keys = from.GetOwnPropertyKeys();
+                foreach (var nextKey in keys)
+                {
+                    var desc = from.GetOwnProperty(nextKey);
+                    if (desc != PropertyDescriptor.Undefined && desc.Enumerable)
+                    {
+                        var propValue = from.Get(nextKey);
+                        to.Set(nextKey, propValue, throwOnError: true);
+                    }
+                }
+            }
+            return to;
+        }
+
+        private JsValue Entries(JsValue thisObject, JsValue[] arguments)
+        {
+            var obj = TypeConverter.ToObject(_engine, arguments.At(0));
+            var nameList = obj.EnumerableOwnPropertyNames(EnumerableOwnPropertyNamesKind.KeyValue);
+            return nameList;
+        }
+
+        private JsValue FromEntries(JsValue thisObject, JsValue[] arguments)
+        {
+            var iterable = arguments.At(0);
+            TypeConverter.CheckObjectCoercible(_engine, iterable);
+
+            var obj = _engine.Object.Construct(0);
+
+            var adder = CreateDataPropertyOnObject.Instance;
+            var iterator = arguments.At(0).GetIterator(_engine);
+
+            IteratorProtocol.AddEntriesFromIterable(obj, iterator, adder);
+
+            return obj;
+        }
+
+        private static JsValue Is(JsValue thisObject, JsValue[] arguments)
+        {
+            return SameValue(arguments.At(0), arguments.At(1));
+        }
+
         public ObjectPrototype PrototypeObject { get; private set; }
 
         /// <summary>
@@ -127,7 +192,7 @@ namespace Jint.Native.Object
             return obj.Prototype ?? Null;
         }
 
-        public JsValue SetPrototypeOf(JsValue thisObject, JsValue[] arguments)
+        private JsValue SetPrototypeOf(JsValue thisObject, JsValue[] arguments)
         {
             var oArg = arguments.At(0);
             TypeConverter.CheckObjectCoercible(_engine, oArg);
@@ -150,9 +215,9 @@ namespace Jint.Native.Object
             return o;
         }
 
-        public JsValue GetOwnPropertyDescriptor(JsValue thisObject, JsValue[] arguments)
+        internal JsValue GetOwnPropertyDescriptor(JsValue thisObject, JsValue[] arguments)
         {
-            var o = arguments.As<ObjectInstance>(0, _engine);
+            var o = TypeConverter.ToObject(_engine, arguments.At(0));
 
             var p = arguments.At(1);
             var name = TypeConverter.ToPropertyKey(p);
@@ -161,45 +226,38 @@ namespace Jint.Native.Object
             return PropertyDescriptor.FromPropertyDescriptor(Engine, desc);
         }
 
-        public JsValue GetOwnPropertyNames(JsValue thisObject, JsValue[] arguments)
+        private JsValue GetOwnPropertyDescriptors(JsValue thisObject, JsValue[] arguments)
         {
-            var o = arguments.As<ObjectInstance>(0, _engine);
-
-            uint n = 0;
-
-            ArrayInstance array = null;
-            var ownProperties = o.GetOwnPropertyKeys(Types.String);
-            if (o is StringInstance s)
+            var o = TypeConverter.ToObject(_engine, arguments.At(0));
+            var ownKeys = o.GetOwnPropertyKeys();
+            var descriptors = _engine.Object.Construct(0);
+            foreach (var key in ownKeys)
             {
-                var length = s.PrimitiveValue.Length;
-                array = Engine.Array.ConstructFast((uint) (ownProperties.Count + length + 1));
-                for (var i = 0; i < length; i++)
+                var desc = o.GetOwnProperty(key);
+                var descriptor = PropertyDescriptor.FromPropertyDescriptor(Engine, desc);
+                if (descriptor != Undefined)
                 {
-                    array.SetIndexValue(n++, TypeConverter.ToString(i), updateLength: false);
+                    descriptors.CreateDataProperty(key, descriptor);
                 }
-
-                array.SetIndexValue(n++, CommonProperties.Length, updateLength: false);
-            }
-
-            array = array ?? Engine.Array.ConstructFast((uint) ownProperties.Count);
-            for (var i = 0; i < ownProperties.Count; i++)
-            {
-                var p = ownProperties[i];
-                array.SetIndexValue(n++, p, false);
             }
+            return descriptors;
+        }
 
-            array.SetLength(n);
-            return array;
+        public JsValue GetOwnPropertyNames(JsValue thisObject, JsValue[] arguments)
+        {
+            var o = TypeConverter.ToObject(_engine, arguments.At(0));
+            var names = o.GetOwnPropertyKeys(Types.String);
+            return _engine.Array.Construct(names.ToArray());
         }
 
-        public JsValue GetOwnPropertySymbols(JsValue thisObject, JsValue[] arguments)
+        private JsValue GetOwnPropertySymbols(JsValue thisObject, JsValue[] arguments)
         {
-            var o = arguments.As<ObjectInstance>(0, _engine);
+            var o = TypeConverter.ToObject(_engine, arguments.At(0));
             var keys = o.GetOwnPropertyKeys(Types.Symbol);
             return _engine.Array.Construct(keys.ToArray());
         }
 
-        public JsValue Create(JsValue thisObject, JsValue[] arguments)
+        private JsValue Create(JsValue thisObject, JsValue[] arguments)
         {
             var prototype = arguments.At(0);
             if (!prototype.IsObject() && !prototype.IsNull())
@@ -223,7 +281,7 @@ namespace Jint.Native.Object
             return obj;
         }
 
-        public JsValue DefineProperty(JsValue thisObject, JsValue[] arguments)
+        private JsValue DefineProperty(JsValue thisObject, JsValue[] arguments)
         {
             var o = arguments.As<ObjectInstance>(0, _engine);
             var p = arguments.At(1);
@@ -236,7 +294,7 @@ namespace Jint.Native.Object
             return o;
         }
 
-        public JsValue DefineProperties(JsValue thisObject, JsValue[] arguments)
+        private JsValue DefineProperties(JsValue thisObject, JsValue[] arguments)
         {
             var o = arguments.As<ObjectInstance>(0, _engine);
             var properties = arguments.At(1);
@@ -261,9 +319,13 @@ namespace Jint.Native.Object
             return o;
         }
 
-        public JsValue Seal(JsValue thisObject, JsValue[] arguments)
+        private JsValue Seal(JsValue thisObject, JsValue[] arguments)
         {
-            var o = arguments.As<ObjectInstance>(0, _engine);
+            if (!(arguments.At(0) is ObjectInstance o))
+            {
+                return arguments.At(0);
+            }
+
             var properties = new List<KeyValuePair<JsValue, PropertyDescriptor>>(o.GetOwnProperties());
             foreach (var prop in properties)
             {
@@ -282,11 +344,14 @@ namespace Jint.Native.Object
             return o;
         }
 
-        public JsValue Freeze(JsValue thisObject, JsValue[] arguments)
+        private static JsValue Freeze(JsValue thisObject, JsValue[] arguments)
         {
-            var o = arguments.As<ObjectInstance>(0, _engine);
-            var properties = new List<KeyValuePair<JsValue, PropertyDescriptor>>(o.GetOwnProperties());
-            foreach (var p in properties)
+            if (!(arguments.At(0) is ObjectInstance o))
+            {
+                return arguments.At(0);
+            }
+
+            foreach (var p in o.GetOwnProperties())
             {
                 var desc = o.GetOwnProperty(p.Key);
                 if (desc.IsDataDescriptor())
@@ -312,16 +377,24 @@ namespace Jint.Native.Object
             return o;
         }
 
-        public JsValue PreventExtensions(JsValue thisObject, JsValue[] arguments)
+        private static JsValue PreventExtensions(JsValue thisObject, JsValue[] arguments)
         {
-            var o = arguments.As<ObjectInstance>(0, _engine);
+            if (!(arguments.At(0) is ObjectInstance o))
+            {
+                return arguments.At(0);
+            }
+
             o.PreventExtensions();
             return o;
         }
 
-        public JsValue IsSealed(JsValue thisObject, JsValue[] arguments)
+        private static JsValue IsSealed(JsValue thisObject, JsValue[] arguments)
         {
-            var o = arguments.As<ObjectInstance>(0, _engine);
+            if (!(arguments.At(0) is ObjectInstance o))
+            {
+                return arguments.At(0);
+            }
+
             foreach (var prop in o.GetOwnProperties())
             {
                 if (prop.Value.Configurable)
@@ -338,9 +411,13 @@ namespace Jint.Native.Object
             return false;
         }
 
-        public JsValue IsFrozen(JsValue thisObject, JsValue[] arguments)
+        private static JsValue IsFrozen(JsValue thisObject, JsValue[] arguments)
         {
-            var o = arguments.As<ObjectInstance>(0, _engine);
+            if (!(arguments.At(0) is ObjectInstance o))
+            {
+                return arguments.At(0);
+            }
+
             foreach (var pair in o.GetOwnProperties())
             {
                 var desc = pair.Value;
@@ -365,65 +442,47 @@ namespace Jint.Native.Object
             return false;
         }
 
-        public JsValue IsExtensible(JsValue thisObject, JsValue[] arguments)
+        private static JsValue IsExtensible(JsValue thisObject, JsValue[] arguments)
         {
-            var o = arguments.As<ObjectInstance>(0, _engine);
+            if (!(arguments.At(0) is ObjectInstance o))
+            {
+                return arguments.At(0);
+            }
+
             return o.Extensible;
         }
 
-        public JsValue Keys(JsValue thisObject, JsValue[] arguments)
+        private JsValue Keys(JsValue thisObject, JsValue[] arguments)
         {
-            return EnumerableOwnPropertyNames(arguments, EnumerableOwnPropertyNamesKind.Key);
+            var o = TypeConverter.ToObject(_engine, arguments.At(0));
+            return o.EnumerableOwnPropertyNames(EnumerableOwnPropertyNamesKind.Key);
         }
 
-        private JsValue EnumerableOwnPropertyNames(JsValue[] arguments, EnumerableOwnPropertyNamesKind kind)
+        private JsValue Values(JsValue thisObject, JsValue[] arguments)
         {
-            var o = arguments.As<ObjectInstance>(0, _engine);
-            var ownKeys = o.GetOwnPropertyKeys(Types.String);
+            var o = TypeConverter.ToObject(_engine, arguments.At(0));
+            return o.EnumerableOwnPropertyNames(EnumerableOwnPropertyNamesKind.Value);
+        }
 
-            var array = Engine.Array.ConstructFast((uint) ownKeys.Count);
-            uint index = 0;
+        private sealed class CreateDataPropertyOnObject : ICallable
+        {
+            internal static readonly CreateDataPropertyOnObject Instance = new CreateDataPropertyOnObject();
 
-            for (var i = 0; i < ownKeys.Count; i++)
+            private CreateDataPropertyOnObject()
             {
-                var property = ownKeys[i];
-                var desc = o.GetOwnProperty(property);
-                if (desc != PropertyDescriptor.Undefined && desc.Enumerable)
-                {
-                    if (kind == EnumerableOwnPropertyNamesKind.Key)
-                    {
-                        array.SetIndexValue(index, property, updateLength: false);
-                    }
-                    else
-                    {
-                        var value = o.Get(property, o);
-                        if (kind == EnumerableOwnPropertyNamesKind.Value)
-                        {
-                            array.SetIndexValue(index, value, updateLength: false);
-                        }
-                        else
-                        {
-                            array.SetIndexValue(index, _engine.Array.Construct(new[]
-                            {
-                                property,
-                                value
-                            }), updateLength: false);
-                        }
-                    }
-
-                    index++;
-                }
             }
 
-            array.SetLength(index);
-            return array;
-        }
+            public JsValue Call(JsValue thisObject, JsValue[] arguments)
+            {
+                var o = (ObjectInstance) thisObject;
+                var key = arguments.At(0);
+                var value = arguments.At(1);
+                var propertyKey = TypeConverter.ToPropertyKey(key);
 
-        private enum EnumerableOwnPropertyNamesKind
-        {
-            Key,
-            Value,
-            KeyValue
+                o.CreateDataPropertyOrThrow(propertyKey, value);
+
+                return Undefined;
+            }
         }
     }
 }

+ 66 - 11
Jint/Native/Object/ObjectInstance.cs

@@ -87,7 +87,7 @@ namespace Jint.Native.Object
         internal ObjectInstance Construct(IConstructor f, JsValue[] argumentsList = null, IConstructor newTarget = null)
         {
             newTarget ??= f;
-            argumentsList ??= ArrayExt.Empty<JsValue>();
+            argumentsList ??= System.Array.Empty<JsValue>();
             return f.Construct(argumentsList, (JsValue) newTarget);
         }
 
@@ -213,7 +213,7 @@ namespace Jint.Native.Object
             }
         }
 
-        public virtual List<JsValue> GetOwnPropertyKeys(Types types)
+        public virtual List<JsValue> GetOwnPropertyKeys(Types types = Types.String | Types.Symbol)
         {
             EnsureInitialized();
 
@@ -1197,23 +1197,78 @@ namespace Jint.Native.Object
             return jsValue as ICallable ?? ExceptionHelper.ThrowTypeError<ICallable>(engine, "Value returned for property '" + p + "' of object is not a function");
         }
 
-        internal ObjectInstance CreateRestObject(
-            HashSet<string> processedProperties)
+        internal void CopyDataProperties(
+            ObjectInstance target,
+            HashSet<JsValue> processedProperties)
         {
-            var rest = _engine.Object.Construct(_properties.Count - processedProperties.Count);
-            foreach (var pair in _properties)
+            var keys = GetOwnPropertyKeys();
+            for (var i = 0; i < keys.Count; i++)
             {
-                if (!processedProperties.Contains(pair.Key))
+                var key = keys[i];
+                if (processedProperties == null || !processedProperties.Contains(key))
                 {
-                    var descriptor = pair.Value;
-                    if (descriptor.Enumerable)
+                    var desc = GetOwnProperty(key);
+                    if (desc.Enumerable)
                     {
-                        rest.SetDataProperty(pair.Key, UnwrapJsValue(descriptor, this));
+                        target.CreateDataProperty(key, UnwrapJsValue(desc, this));
                     }
                 }
             }
+        }
+
+        internal JsValue EnumerableOwnPropertyNames(EnumerableOwnPropertyNamesKind kind)
+        {
+            var ownKeys = GetOwnPropertyKeys(Types.String);
+
+            var array = Engine.Array.ConstructFast((uint) ownKeys.Count);
+            uint index = 0;
+
+            for (var i = 0; i < ownKeys.Count; i++)
+            {
+                var property = ownKeys[i];
+
+                if (!property.IsString())
+                {
+                    continue;
+                }
+                
+                var desc = GetOwnProperty(property);
+                if (desc != PropertyDescriptor.Undefined && desc.Enumerable)
+                {
+                    if (kind == EnumerableOwnPropertyNamesKind.Key)
+                    {
+                        array.SetIndexValue(index, property, updateLength: false);
+                    }
+                    else
+                    {
+                        var value = Get(property);
+                        if (kind == EnumerableOwnPropertyNamesKind.Value)
+                        {
+                            array.SetIndexValue(index, value, updateLength: false);
+                        }
+                        else
+                        {
+                            array.SetIndexValue(index, _engine.Array.Construct(new[]
+                            {
+                                property,
+                                value
+                            }), updateLength: false);
+                        }
+                    }
+
+                    index++;
+                }
+            }
 
-            return rest;
+            array.SetLength(index);
+            return array;
+        }
+
+        internal enum EnumerableOwnPropertyNamesKind
+        {
+            Key,
+            Value,
+            KeyValue
         }
 
         internal ObjectInstance AssertThisIsObjectInstance(JsValue value, string methodName)

+ 19 - 13
Jint/Native/Object/ObjectPrototype.cs

@@ -1,4 +1,5 @@
 using Jint.Collections;
+using Jint.Native.Symbol;
 using Jint.Runtime;
 using Jint.Runtime.Descriptors;
 using Jint.Runtime.Interop;
@@ -26,15 +27,16 @@ namespace Jint.Native.Object
         protected override void Initialize()
         {
             const PropertyFlag propertyFlags = PropertyFlag.Configurable | PropertyFlag.Writable;
+            const PropertyFlag lengthFlags = PropertyFlag.Configurable;
             var properties = new PropertyDictionary(8, checkExistingKeys: false)
             {
                 ["constructor"] = new PropertyDescriptor(_objectConstructor, propertyFlags),
-                ["toString"] = new PropertyDescriptor(new ClrFunctionInstance(Engine, "toString", ToObjectString), propertyFlags),
-                ["toLocaleString"] = new PropertyDescriptor(new ClrFunctionInstance(Engine, "toLocaleString", ToLocaleString), propertyFlags),
-                ["valueOf"] = new PropertyDescriptor(new ClrFunctionInstance(Engine, "valueOF", ValueOf), propertyFlags),
-                ["hasOwnProperty"] = new PropertyDescriptor(new ClrFunctionInstance(Engine, "hasOwnProperty", HasOwnProperty, 1), propertyFlags),
-                ["isPrototypeOf"] = new PropertyDescriptor(new ClrFunctionInstance(Engine, "isPrototypeOf", IsPrototypeOf, 1), propertyFlags),
-                ["propertyIsEnumerable"] = new PropertyDescriptor(new ClrFunctionInstance(Engine, "propertyIsEnumerable", PropertyIsEnumerable, 1), propertyFlags)
+                ["toString"] = new PropertyDescriptor(new ClrFunctionInstance(Engine, "toString", ToObjectString, 0, lengthFlags), propertyFlags),
+                ["toLocaleString"] = new PropertyDescriptor(new ClrFunctionInstance(Engine, "toLocaleString", ToLocaleString, 0, lengthFlags), propertyFlags),
+                ["valueOf"] = new PropertyDescriptor(new ClrFunctionInstance(Engine, "valueOf", ValueOf, 0, lengthFlags), propertyFlags),
+                ["hasOwnProperty"] = new PropertyDescriptor(new ClrFunctionInstance(Engine, "hasOwnProperty", HasOwnProperty, 1, lengthFlags), propertyFlags),
+                ["isPrototypeOf"] = new PropertyDescriptor(new ClrFunctionInstance(Engine, "isPrototypeOf", IsPrototypeOf, 1, lengthFlags), propertyFlags),
+                ["propertyIsEnumerable"] = new PropertyDescriptor(new ClrFunctionInstance(Engine, "propertyIsEnumerable", PropertyIsEnumerable, 1, lengthFlags), propertyFlags)
             };
             SetProperties(properties);
         }
@@ -88,12 +90,9 @@ namespace Jint.Native.Object
         private JsValue ToLocaleString(JsValue thisObject, JsValue[] arguments)
         {
             var o = TypeConverter.ToObject(Engine, thisObject);
-            var toString = o.Get("toString", o).TryCast<ICallable>(x =>
-            {
-                ExceptionHelper.ThrowTypeError(Engine);
-            });
-
-            return toString.Call(o, Arguments.Empty);
+            var func = o.Get("toString");
+            var callable = func as ICallable ?? ExceptionHelper.ThrowTypeErrorNoEngine<ICallable>("Can only invoke functions");
+            return TypeConverter.ToString(callable.Call(thisObject, arguments));
         }
 
         /// <summary>
@@ -115,7 +114,14 @@ namespace Jint.Native.Object
             }
 
             var o = TypeConverter.ToObject(Engine, thisObject);
-            return "[object " + o.Class + "]";
+
+            var tag = o.Get(GlobalSymbolRegistry.ToStringTag);
+            if (!tag.IsString())
+            {
+                tag = o.Class.ToString();
+            }
+
+            return "[object " + tag + "]";
         }
 
         /// <summary>

+ 2 - 3
Jint/Native/Proxy/ProxyConstructor.cs

@@ -1,5 +1,4 @@
-using System;
-using Jint.Collections;
+using Jint.Collections;
 using Jint.Native.Function;
 using Jint.Native.Object;
 using Jint.Runtime;
@@ -77,7 +76,7 @@ namespace Jint.Native.Proxy
         private JsValue Revocable(JsValue thisObject, JsValue[] arguments)
         {
             var p = _engine.Proxy.Construct(arguments, Undefined);
-            var result = _engine.Object.Construct(ArrayExt.Empty<JsValue>());
+            var result = _engine.Object.Construct(System.Array.Empty<JsValue>());
             result.DefineOwnProperty(PropertyRevoke, new PropertyDescriptor(new ClrFunctionInstance(_engine, name: null, Revoke, 0, PropertyFlag.Configurable), PropertyFlag.ConfigurableEnumerableWritable));
             result.DefineOwnProperty(PropertyProxy, new PropertyDescriptor(Construct(arguments, thisObject), PropertyFlag.ConfigurableEnumerableWritable));
             return result;

+ 5 - 7
Jint/Native/Proxy/ProxyInstance.cs

@@ -26,12 +26,13 @@ namespace Jint.Native.Proxy
         private static readonly JsString TrapConstruct = new JsString("construct");
 
         private static readonly JsString KeyFunctionRevoke = new JsString("revoke");
+        private static readonly JsString KeyIsArray = new JsString("isArray");
 
         public ProxyInstance(
             Engine engine,
             ObjectInstance target,
             ObjectInstance handler)
-            : base(engine, JsString.Empty, false, ObjectClass.Proxy)
+            : base(engine, JsString.Empty, false, target.Class)
         {
             _target = target;
             _handler = handler;
@@ -71,10 +72,7 @@ namespace Jint.Native.Proxy
 
         public override bool IsArray()
         {
-            if (_handler is null)
-            {
-                return ExceptionHelper.ThrowTypeError<bool>(_engine);
-            }
+            AssertNotRevoked(KeyIsArray);
             return _target.IsArray();
         }
 
@@ -183,7 +181,7 @@ namespace Jint.Native.Proxy
 
         public override PropertyDescriptor GetOwnProperty(JsValue property)
         {
-            if (!TryCallHandler(TrapGetOwnPropertyDescriptor, new JsValue[] {_target, property, this}, out var result))
+            if (!TryCallHandler(TrapGetOwnPropertyDescriptor, new[] {_target, property, this}, out var result))
             {
                 return _target.GetOwnProperty(property);
             }
@@ -474,7 +472,7 @@ namespace Jint.Native.Proxy
             }
         }
 
-        internal void AssertTargetNotRevoked(JsValue key)
+        private void AssertTargetNotRevoked(JsValue key)
         {
             if (_target is null)
             {

+ 12 - 2
Jint/Native/Reflect/ReflectInstance.cs

@@ -140,6 +140,10 @@ namespace Jint.Native.Reflect
 
         private JsValue GetOwnPropertyDescriptor(JsValue thisObject, JsValue[] arguments)
         {
+            if (!arguments.At(0).IsObject())
+            {
+                ExceptionHelper.ThrowTypeError(_engine, "Reflect.getOwnPropertyDescriptor called on non-object");
+            }
             return _engine.Object.GetOwnPropertyDescriptor(Undefined, arguments);
         }
 
@@ -151,13 +155,19 @@ namespace Jint.Native.Reflect
                 return ExceptionHelper.ThrowTypeError<JsValue>(_engine, "Reflect.get called on non-object");
             }
 
-            var keys = o.GetOwnPropertyKeys(Types.String | Types.Symbol);
+            var keys = o.GetOwnPropertyKeys();
             return _engine.Array.CreateArrayFromList(keys);
         }
 
         private JsValue IsExtensible(JsValue thisObject, JsValue[] arguments)
         {
-            return _engine.Object.IsExtensible(Undefined, arguments);
+            var target = arguments.At(0);
+            if (!(target is ObjectInstance o))
+            {
+                return ExceptionHelper.ThrowTypeError<JsValue>(_engine, "Reflect.isExtensible called on non-object");
+            }
+
+            return o.Extensible;
         }
 
         private JsValue PreventExtensions(JsValue thisObject, JsValue[] arguments)

+ 1 - 1
Jint/Native/String/StringConstructor.cs

@@ -30,7 +30,7 @@ namespace Jint.Native.String
             // The value of the [[Prototype]] internal property of the String constructor is the Function prototype object
             obj.PrototypeObject = StringPrototype.CreatePrototypeObject(engine, obj);
 
-            obj._length = PropertyDescriptor.AllForbiddenDescriptor.NumberOne;
+            obj._length = new PropertyDescriptor(JsNumber.One, PropertyFlag.Configurable);
 
             // The initial value of String.prototype is the String prototype object
             obj._prototypeDescriptor = new PropertyDescriptor(obj.PrototypeObject, PropertyFlag.AllForbidden);

+ 16 - 0
Jint/Native/String/StringInstance.cs

@@ -78,6 +78,22 @@ namespace Jint.Native.String
             }
         }
 
+        public override List<JsValue> GetOwnPropertyKeys(Types types)
+        {
+            var keys = new List<JsValue>(PrimitiveValue.Length + 1);
+            for (uint i = 0; i < PrimitiveValue.Length; ++i)
+            {
+                keys.Add(JsString.Create(i));
+            }
+
+            keys.AddRange(base.GetOwnPropertyKeys(types));
+            keys.Sort((v1, v2) => TypeConverter.ToNumber(v1).CompareTo(TypeConverter.ToNumber(v2)));
+
+            keys.Add(JsString.LengthString);
+
+            return keys;
+        }
+
         protected internal override void SetOwnProperty(JsValue property, PropertyDescriptor desc)
         {
             if (property == CommonProperties.Length)

+ 1 - 1
Jint/Native/String/StringPrototype.cs

@@ -501,7 +501,7 @@ namespace Jint.Native.String
             }
             else
             {
-                var captures = ArrayExt.Empty<string>();
+                var captures = System.Array.Empty<string>();
                 replStr =  RegExpPrototype.GetSubstitution(matched, thisString.ToString(), pos, captures, Undefined, TypeConverter.ToString(replaceValue));
             }
 

+ 2 - 3
Jint/Pooling/JsValueArrayPool.cs

@@ -1,5 +1,4 @@
-using System;
-using System.Runtime.CompilerServices;
+using System.Runtime.CompilerServices;
 using Jint.Native;
 
 namespace Jint.Pooling
@@ -41,7 +40,7 @@ namespace Jint.Pooling
         {
             if (size == 0)
             {
-                return ArrayExt.Empty<JsValue>();
+                return System.Array.Empty<JsValue>();
             }
             if (size == 1)
             {

+ 2 - 2
Jint/Runtime/Arguments.cs

@@ -6,7 +6,7 @@ namespace Jint.Runtime
 {
     public static class Arguments
     {
-        public static readonly JsValue[] Empty = ArrayExt.Empty<JsValue>();
+        public static readonly JsValue[] Empty = Array.Empty<JsValue>();
 
         public static JsValue[] From(params JsValue[] o)
         {
@@ -50,7 +50,7 @@ namespace Jint.Runtime
             var newLength = args.Length - count;
             if (newLength <= 0)
             {
-                return ArrayExt.Empty<JsValue>();
+                return Array.Empty<JsValue>();
             }
 
             var array = new JsValue[newLength];

+ 6 - 6
Jint/Runtime/Environments/DeclarativeEnvironmentRecord.cs

@@ -1,5 +1,4 @@
-using System;
-using System.Collections.Generic;
+using System.Collections.Generic;
 using System.Runtime.CompilerServices;
 using Esprima.Ast;
 using Jint.Collections;
@@ -128,7 +127,7 @@ namespace Jint.Runtime.Environments
         {
             if (_dictionary is null)
             {
-                return ArrayExt.Empty<string>();
+                return System.Array.Empty<string>();
             }
 
             var keys = new string[_dictionary.Count];
@@ -198,7 +197,7 @@ namespace Jint.Runtime.Environments
                 }
 
                 ArrayInstance array = null;
-                var arrayContents = ArrayExt.Empty<JsValue>();
+                var arrayContents = System.Array.Empty<JsValue>();
                 if (argument.IsArray())
                 {
                     array = argument.AsArray();
@@ -240,7 +239,7 @@ namespace Jint.Runtime.Environments
                 var argumentObject = argument.AsObject();
 
                 var processedProperties = objectPattern.Properties.Count > 0 && objectPattern.Properties[objectPattern.Properties.Count - 1] is RestElement
-                    ? new HashSet<string>()
+                    ? new HashSet<JsValue>()
                     : null;
 
                 var jsValues = _engine._jsValueArrayPool.RentArray(1);
@@ -275,7 +274,8 @@ namespace Jint.Runtime.Environments
                     {
                         if (((RestElement) property).Argument is Identifier restIdentifier)
                         {
-                            var rest = argumentObject.CreateRestObject(processedProperties);
+                            var rest = _engine.Object.Construct(argumentObject.Properties.Count - processedProperties.Count);
+                            argumentObject.CopyDataProperties(rest, processedProperties);
                             SetItemSafely(restIdentifier.Name, rest, initiallyEmpty);
                         }
                         else

+ 2 - 3
Jint/Runtime/Environments/ObjectEnvironmentRecord.cs

@@ -1,5 +1,4 @@
-using System;
-using System.Linq;
+using System.Linq;
 using Jint.Native;
 using Jint.Native.Object;
 using Jint.Native.Symbol;
@@ -128,7 +127,7 @@ namespace Jint.Runtime.Environments
                 return _bindingObject.GetOwnProperties().Select( x=> x.Key.ToString()).ToArray();
             }
 
-            return ArrayExt.Empty<string>();
+            return System.Array.Empty<string>();
         }
 
         public override bool Equals(JsValue other)

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

@@ -146,7 +146,7 @@ namespace Jint.Runtime.Interop
                 {
                     if (type == typeof(Action))
                     {
-                        return (Action)(() => function(JsValue.Undefined, ArrayExt.Empty<JsValue>()));
+                        return (Action)(() => function(JsValue.Undefined, System.Array.Empty<JsValue>()));
                     }
                     else if (typeof(MulticastDelegate).IsAssignableFrom(type))
                     {
@@ -239,7 +239,7 @@ namespace Jint.Runtime.Interop
                 }
 
                 var dict = (IDictionary<string, object>) eObj;
-                var obj = Activator.CreateInstance(type, ArrayExt.Empty<object>());
+                var obj = Activator.CreateInstance(type, System.Array.Empty<object>());
 
                 var members = type.GetMembers();
                 foreach (var member in members)

+ 3 - 2
Jint/Runtime/Interpreter/Expressions/BindingPatternAssignmentExpression.cs

@@ -193,7 +193,7 @@ namespace Jint.Runtime.Interpreter.Expressions
         private static void HandleObjectPattern(Engine engine, ObjectPattern pattern, JsValue argument)
         {
             var processedProperties = pattern.Properties.Count > 0 && pattern.Properties[pattern.Properties.Count - 1] is RestElement
-                ? new HashSet<string>()
+                ? new HashSet<JsValue>()
                 : null;
 
             var source = TypeConverter.ToObject(engine, argument);
@@ -254,7 +254,8 @@ namespace Jint.Runtime.Interpreter.Expressions
                     var restElement = (RestElement) pattern.Properties[i];
                     if (restElement.Argument is Identifier leftIdentifier)
                     {
-                        var rest = source.CreateRestObject(processedProperties);
+                        var rest = engine.Object.Construct(source.Properties.Count - processedProperties.Count);
+                        source.CopyDataProperties(rest, processedProperties);
                         AssignToIdentifier(engine, leftIdentifier.Name, rest);
                     }
                     else if (restElement.Argument is BindingPattern bp)

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

@@ -415,7 +415,7 @@ namespace Jint.Runtime.Interpreter.Expressions
                     return ExceptionHelper.ThrowTypeError<JsValue>(_engine, "in can only be used with an object");
                 }
 
-                return oi.HasProperty(TypeConverter.ToJsString(left)) ? JsBoolean.True : JsBoolean.False;
+                return oi.HasProperty(left) ? JsBoolean.True : JsBoolean.False;
             }
         }
 

+ 2 - 3
Jint/Runtime/Interpreter/Expressions/JintCallExpression.cs

@@ -1,4 +1,3 @@
-using System;
 using Esprima.Ast;
 using Jint.Native;
 using Jint.Native.Function;
@@ -59,7 +58,7 @@ namespace Jint.Runtime.Interpreter.Expressions
             if (cacheable)
             {
                 _cached = true;
-                var arguments = ArrayExt.Empty<JsValue>();
+                var arguments = System.Array.Empty<JsValue>();
                 if (cachedArgumentsHolder.JintArguments.Length > 0)
                 {
                     arguments = new JsValue[cachedArgumentsHolder.JintArguments.Length];
@@ -85,7 +84,7 @@ namespace Jint.Runtime.Interpreter.Expressions
             // todo: implement as in http://www.ecma-international.org/ecma-262/5.1/#sec-11.2.4
 
             var cachedArguments = _cachedArguments;
-            var arguments = ArrayExt.Empty<JsValue>();
+            var arguments = System.Array.Empty<JsValue>();
             if (_cached)
             {
                 arguments = cachedArguments.CachedArguments;

+ 41 - 18
Jint/Runtime/Interpreter/Expressions/JintObjectExpression.cs

@@ -1,8 +1,8 @@
-using System;
 using Esprima.Ast;
 using Jint.Collections;
 using Jint.Native;
 using Jint.Native.Function;
+using Jint.Native.Object;
 using Jint.Runtime.Descriptors;
 using Jint.Runtime.Descriptors.Specialized;
 
@@ -13,8 +13,8 @@ namespace Jint.Runtime.Interpreter.Expressions
     /// </summary>
     internal sealed class JintObjectExpression : JintExpression
     {
-        private JintExpression[] _valueExpressions = ArrayExt.Empty<JintExpression>();
-        private ObjectProperty[] _properties = ArrayExt.Empty<ObjectProperty>();
+        private JintExpression[] _valueExpressions = System.Array.Empty<JintExpression>();
+        private ObjectProperty[] _properties = System.Array.Empty<ObjectProperty>();
 
         // check if we can do a shortcut when all are object properties
         // and don't require duplicate checking
@@ -55,30 +55,42 @@ namespace Jint.Runtime.Interpreter.Expressions
 
             for (var i = 0; i < _properties.Length; i++)
             {
-                var property = (Property) expression.Properties[i];
                 string propName = null;
-
-                if (property.Key is Literal literal)
+                var property = expression.Properties[i];
+                if (property is Property p)
                 {
-                    propName = EsprimaExtensions.LiteralKeyToString(literal);
-                }
+                    if (p.Key is Literal literal)
+                    {
+                        propName = EsprimaExtensions.LiteralKeyToString(literal);
+                    }
 
-                if (!property.Computed && property.Key is Identifier identifier)
-                {
-                    propName = identifier.Name;
-                }
+                    if (!p.Computed && p.Key is Identifier identifier)
+                    {
+                        propName = identifier.Name;
+                    }
 
-                _properties[i] = new ObjectProperty(propName, property);
+                    _properties[i] = new ObjectProperty(propName, p);
 
-                if (property.Kind == PropertyKind.Init || property.Kind == PropertyKind.Data)
+                    if (p.Kind == PropertyKind.Init || p.Kind == PropertyKind.Data)
+                    {
+                        var propertyValue = (Expression) p.Value;
+                        _valueExpressions[i] = Build(_engine, propertyValue);
+                        _canBuildFast &= !propertyValue.IsFunctionWithName();
+                    }
+                    else
+                    {
+                        _canBuildFast = false;
+                    }
+                }
+                else if (property is SpreadElement spreadElement)
                 {
-                    var propertyValue = (Expression) property.Value;
-                    _valueExpressions[i] = Build(_engine, propertyValue);
-                    _canBuildFast &= !propertyValue.IsFunctionWithName();
+                    _canBuildFast = false;
+                    _properties[i] = null;
+                    _valueExpressions[i] = Build(_engine, spreadElement.Argument);
                 }
                 else
                 {
-                    _canBuildFast = false;
+                    ExceptionHelper.ThrowArgumentOutOfRangeException("property", "cannot handle property " + property);
                 }
 
                 _canBuildFast &= propName != null;
@@ -123,6 +135,17 @@ namespace Jint.Runtime.Interpreter.Expressions
             for (var i = 0; i < _properties.Length; i++)
             {
                 var objectProperty = _properties[i];
+
+                if (objectProperty is null)
+                {
+                    // spread
+                    if (_valueExpressions[i].GetValue() is ObjectInstance source)
+                    {
+                        source.CopyDataProperties(obj, null);
+                    }
+                    continue;
+                }
+                
                 var property = objectProperty._value;
                 var propName = objectProperty.KeyJsString ?? property.GetKey(_engine);
 

+ 1 - 1
Jint/Runtime/RefStack.cs

@@ -79,7 +79,7 @@ namespace Jint.Runtime
                 }
                 else
                 {
-                    _array = ArrayExt.Empty<ExecutionContext>();
+                    _array = Array.Empty<ExecutionContext>();
                 }
             }
         }

+ 7 - 18
Jint/Runtime/TypeConverter.cs

@@ -119,7 +119,7 @@ namespace Jint.Runtime
         /// </summary>
         internal static JsValue OrdinaryToPrimitive(ObjectInstance input, Types hint = Types.None)
         {
-            var callOrder = ArrayExt.Empty<JsString>();
+            var callOrder = Array.Empty<JsString>();
             if (hint == Types.String)
             {
                 callOrder = StringHintCallOrder;
@@ -441,7 +441,11 @@ namespace Jint.Runtime
         [MethodImpl(MethodImplOptions.NoInlining)]
         private static JsValue ToPropertyKeyNonString(JsValue o)
         {
-            return new JsString(ToStringNonString(ToPrimitive(o, Types.String)));
+            const InternalTypes stringOrSymbol = InternalTypes.String | InternalTypes.Symbol;
+            var primitive = ToPrimitive(o, Types.String);
+            return (primitive._type & stringOrSymbol) != 0
+                ? primitive
+                : ToStringNonString(primitive);
         }
 
         /// <summary>
@@ -513,22 +517,7 @@ namespace Jint.Runtime
                     return null;
             }
         }
-
-        internal static Types GetInternalPrimitiveType(JsValue value)
-        {
-            if (!value.IsObject())
-            {
-                return value.Type;
-            }
-
-            if (value is IPrimitiveInstance primitive)
-            {
-                return primitive.Type;
-            }
-
-            return Types.Object;
-        }
-
+        
         internal static void CheckObjectCoercible(
             Engine engine,
             JsValue o,

+ 1 - 1
README.md

@@ -174,7 +174,7 @@ ES6 features which are being implemented:
 - [x] [number APIs](https://github.com/lukehoban/es6features/blob/master/README.md#math--number--string--array--object-apis)
 - [x] [string APIs](https://github.com/lukehoban/es6features/blob/master/README.md#math--number--string--array--object-apis)
 - [x] [array APIs](https://github.com/lukehoban/es6features/blob/master/README.md#math--number--string--array--object-apis)
-- [ ] [object APIs](https://github.com/lukehoban/es6features/blob/master/README.md#math--number--string--array--object-apis)
+- [x] [object APIs](https://github.com/lukehoban/es6features/blob/master/README.md#math--number--string--array--object-apis)
 - [x] [binary and octal literals](https://github.com/lukehoban/es6features/blob/master/README.md#binary-and-octal-literals)
 - [x] [reflect api](https://github.com/lukehoban/es6features/blob/master/README.md#reflect-api)
 - [ ] [tail calls](https://github.com/lukehoban/es6features/blob/master/README.md#tail-calls)