Browse Source

Merge branch 'dev' into rel/3.0-beta

# Conflicts:
#	appveyor.yml
Sebastien Ros 4 years ago
parent
commit
317ff48943
69 changed files with 1451 additions and 745 deletions
  1. 1 0
      .github/FUNDING.yml
  2. 2 2
      Jint.Benchmark/Jint.Benchmark.csproj
  3. 2 1
      Jint.Repl/Jint.Repl.csproj
  4. 2 2
      Jint.Tests.CommonScripts/Jint.Tests.CommonScripts.csproj
  5. 2 2
      Jint.Tests.Ecma/Jint.Tests.Ecma.csproj
  6. 36 36
      Jint.Tests.Ecma/TestCases/alltests.json
  7. 15 0
      Jint.Tests.Test262/BuiltIns/FunctionTests.cs
  8. 2 2
      Jint.Tests.Test262/Jint.Tests.Test262.csproj
  9. 4 1
      Jint.Tests.Test262/Test262Test.cs
  10. 42 342
      Jint.Tests.Test262/test/skipped.json
  11. 5 2
      Jint.Tests/Jint.Tests.csproj
  12. 22 0
      Jint.Tests/Runtime/ArrayTests.cs
  13. 43 0
      Jint.Tests/Runtime/ConstTests.cs
  14. 6 0
      Jint.Tests/Runtime/DateTests.cs
  15. 12 6
      Jint.Tests/Runtime/Domain/Company.cs
  16. 16 0
      Jint.Tests/Runtime/Domain/HiddenMembers.cs
  17. 18 0
      Jint.Tests/Runtime/Domain/IntegerIndexer.cs
  18. 25 0
      Jint.Tests/Runtime/Domain/JsUuid.cs
  19. 70 0
      Jint.Tests/Runtime/Domain/UuidConstructor.cs
  20. 26 0
      Jint.Tests/Runtime/Domain/UuidConverter.cs
  21. 20 0
      Jint.Tests/Runtime/Domain/UuidInstance.cs
  22. 44 0
      Jint.Tests/Runtime/Domain/UuidPrototype.cs
  23. 73 7
      Jint.Tests/Runtime/EngineTests.cs
  24. 4 4
      Jint.Tests/Runtime/ErrorTests.cs
  25. 211 2
      Jint.Tests/Runtime/InteropTests.cs
  26. 50 0
      Jint.Tests/Runtime/UuidTests.cs
  27. 1 0
      Jint/AssemblyInfoExtras.cs
  28. 1 1
      Jint/Constraints/CancellationConstraint.cs
  29. 3 3
      Jint/Directory.Build.props
  30. 39 49
      Jint/Engine.cs
  31. 1 1
      Jint/Jint.csproj
  32. 1 1
      Jint/Native/Argument/ArgumentsInstance.cs
  33. 14 5
      Jint/Native/Array/ArrayInstance.cs
  34. 1 1
      Jint/Native/Date/DatePrototype.cs
  35. 1 25
      Jint/Native/Function/ArrowFunctionInstance.cs
  36. 4 4
      Jint/Native/Function/BindFunctionInstance.cs
  37. 1 1
      Jint/Native/Function/EvalFunctionInstance.cs
  38. 35 18
      Jint/Native/Function/FunctionConstructor.cs
  39. 47 49
      Jint/Native/Function/FunctionInstance.cs
  40. 60 22
      Jint/Native/Function/FunctionPrototype.cs
  41. 5 5
      Jint/Native/Function/ScriptFunctionInstance.cs
  42. 5 2
      Jint/Native/Function/ThrowTypeError.cs
  43. 2 2
      Jint/Native/Iterator/IteratorInstance.cs
  44. 8 2
      Jint/Native/JsValue.cs
  45. 11 3
      Jint/Native/Object/ObjectConstructor.cs
  46. 2 1
      Jint/Native/Object/ObjectInstance.cs
  47. 10 6
      Jint/Native/Proxy/ProxyInstance.cs
  48. 5 1
      Jint/Native/Reflect/ReflectInstance.cs
  49. 92 13
      Jint/Options.cs
  50. 0 12
      Jint/Runtime/Arguments.cs
  51. 1 1
      Jint/Runtime/Descriptors/Specialized/FieldInfoDescriptor.cs
  52. 12 10
      Jint/Runtime/Descriptors/Specialized/GetSetPropertyDescriptor.cs
  53. 54 28
      Jint/Runtime/Descriptors/Specialized/IndexDescriptor.cs
  54. 3 2
      Jint/Runtime/Descriptors/Specialized/PropertyInfoDescriptor.cs
  55. 5 0
      Jint/Runtime/ExceptionHelper.cs
  56. 9 0
      Jint/Runtime/ExecutionCanceledException.cs
  57. 7 0
      Jint/Runtime/Interop/ClrFunctionInstance.cs
  58. 38 0
      Jint/Runtime/Interop/ClrPropertyDescriptorFactoriesKey.cs
  59. 42 0
      Jint/Runtime/Interop/IReferenceResolver.cs
  60. 125 13
      Jint/Runtime/Interop/ObjectWrapper.cs
  61. 2 3
      Jint/Runtime/Interpreter/Expressions/JintCallExpression.cs
  62. 8 2
      Jint/Runtime/Interpreter/Expressions/JintMemberExpression.cs
  63. 1 1
      Jint/Runtime/Interpreter/Expressions/JintObjectExpression.cs
  64. 1 7
      Jint/Runtime/Interpreter/Expressions/JintUnaryExpression.cs
  65. 13 15
      Jint/Runtime/Interpreter/JintFunctionDefinition.cs
  66. 17 18
      Jint/Runtime/Interpreter/JintStatementList.cs
  67. 1 0
      Jint/Runtime/KnownKeys.cs
  68. 7 5
      Jint/Runtime/TypeConverter.cs
  69. 3 4
      appveyor.yml

+ 1 - 0
.github/FUNDING.yml

@@ -0,0 +1 @@
+github: [lahma, sebastienros]

+ 2 - 2
Jint.Benchmark/Jint.Benchmark.csproj

@@ -1,9 +1,8 @@
 <Project Sdk="Microsoft.NET.Sdk">
   <PropertyGroup>
-    <TargetFramework>netcoreapp3.0</TargetFramework>
+    <TargetFramework>netcoreapp3.1</TargetFramework>
     <AssemblyName>Jint.Benchmark</AssemblyName>
     <OutputType>Exe</OutputType>
-    <PackageId>Jint.Benchmark</PackageId>
     <GenerateAssemblyTitleAttribute>false</GenerateAssemblyTitleAttribute>
     <GenerateAssemblyDescriptionAttribute>false</GenerateAssemblyDescriptionAttribute>
     <GenerateAssemblyConfigurationAttribute>false</GenerateAssemblyConfigurationAttribute>
@@ -15,6 +14,7 @@
     <AssemblyOriginatorKeyFile>..\Jint\Jint.snk</AssemblyOriginatorKeyFile>
     <SignAssembly>true</SignAssembly>
     <LangVersion>8</LangVersion>
+    <IsPackable>false</IsPackable>
   </PropertyGroup>
   <ItemGroup>
     <None Include=".\Scripts\**" CopyToOutputDirectory="PreserveNewest" />

+ 2 - 1
Jint.Repl/Jint.Repl.csproj

@@ -1,7 +1,8 @@
 <Project Sdk="Microsoft.NET.Sdk">
   <PropertyGroup>
-    <TargetFramework>netcoreapp3.0</TargetFramework>
+    <TargetFramework>netcoreapp3.1</TargetFramework>
     <OutputType>Exe</OutputType>
+    <IsPackable>false</IsPackable>
   </PropertyGroup>
   <ItemGroup>
     <ProjectReference Include="..\Jint\Jint.csproj" />

+ 2 - 2
Jint.Tests.CommonScripts/Jint.Tests.CommonScripts.csproj

@@ -9,10 +9,10 @@
     <ProjectReference Include="..\Jint\Jint.csproj" />
   </ItemGroup>
   <ItemGroup>
-    <PackageReference Include="Microsoft.NET.Test.Sdk" Version="16.5.0" />
+    <PackageReference Include="Microsoft.NET.Test.Sdk" Version="16.7.1" />
     <PackageReference Include="xunit" Version="2.4.1" />
     <PackageReference Include="xunit.analyzers" Version="0.10.0" />
-    <PackageReference Include="xunit.runner.visualstudio" Version="2.4.1" />
+    <PackageReference Include="xunit.runner.visualstudio" Version="2.4.3" />
     <PackageReference Include="xunit.runner.console" Version="2.4.1" />
     <DotNetCliToolReference Include="dotnet-xunit" Version="2.3.1" />
   </ItemGroup>

+ 2 - 2
Jint.Tests.Ecma/Jint.Tests.Ecma.csproj

@@ -6,10 +6,10 @@
     <ProjectReference Include="..\Jint\Jint.csproj" />
   </ItemGroup>
   <ItemGroup>
-    <PackageReference Include="Microsoft.NET.Test.Sdk" Version="16.5.0" />
+    <PackageReference Include="Microsoft.NET.Test.Sdk" Version="16.7.1" />
     <PackageReference Include="xunit" Version="2.4.1" />
     <PackageReference Include="xunit.analyzers" Version="0.10.0" />
-    <PackageReference Include="xunit.runner.visualstudio" Version="2.4.1" />
+    <PackageReference Include="xunit.runner.visualstudio" Version="2.4.3" />
     <PackageReference Include="xunit.runner.console" Version="2.4.1" />
     <DotNetCliToolReference Include="dotnet-xunit" Version="2.3.1" />
   </ItemGroup>

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

@@ -16920,8 +16920,8 @@
     source: "ch13/13.2/13.2-28-s.js"
   },
   {
-    skip: false,
-    reason: "",
+    skip: true,
+    reason: "caller no longer present for functions",
     source: "ch13/13.2/13.2-29-s.js"
   },
   {
@@ -16930,38 +16930,38 @@
     source: "ch13/13.2/13.2-3-s.js"
   },
   {
-    skip: false,
-    reason: "",
+    skip: true,
+    reason: "caller no longer present for functions",
     source: "ch13/13.2/13.2-30-s.js"
   },
   {
-    skip: false,
-    reason: "",
+    skip: true,
+    reason: "caller no longer present for functions",
     source: "ch13/13.2/13.2-31-s.js"
   },
   {
-    skip: false,
-    reason: "",
+    skip: true,
+    reason: "caller no longer present for functions",
     source: "ch13/13.2/13.2-32-s.js"
   },
   {
-    skip: false,
-    reason: "",
+    skip: true,
+    reason: "caller no longer present for functions",
     source: "ch13/13.2/13.2-33-s.js"
   },
   {
-    skip: false,
-    reason: "",
+    skip: true,
+    reason: "caller no longer present for functions",
     source: "ch13/13.2/13.2-34-s.js"
   },
   {
-    skip: false,
-    reason: "",
+    skip: true,
+    reason: "caller no longer present for functions",
     source: "ch13/13.2/13.2-35-s.js"
   },
   {
-    skip: false,
-    reason: "",
+    skip: true,
+    reason: "caller no longer present for functions",
     source: "ch13/13.2/13.2-36-s.js"
   },
   {
@@ -37235,8 +37235,8 @@
     source: "ch15/15.3/15.3.4/15.3.4.2/S15.3.4.2_A8.js"
   },
   {
-    skip: false,
-    reason: "",
+    skip: true,
+    reason: "the spec has changed",
     source: "ch15/15.3/15.3.4/15.3.4.2/S15.3.4.2_A9.js"
   },
   {
@@ -37490,8 +37490,8 @@
     source: "ch15/15.3/15.3.4/15.3.4.3/S15.3.4.3_A8_T6.js"
   },
   {
-    skip: false,
-    reason: "",
+    skip: true,
+    reason: "the spec has changed",
     source: "ch15/15.3/15.3.4/15.3.4.3/S15.3.4.3_A9.js"
   },
   {
@@ -37735,8 +37735,8 @@
     source: "ch15/15.3/15.3.4/15.3.4.4/S15.3.4.4_A7_T6.js"
   },
   {
-    skip: false,
-    reason: "",
+    skip: true,
+    reason: "the spec has changed",
     source: "ch15/15.3/15.3.4/15.3.4.4/S15.3.4.4_A9.js"
   },
   {
@@ -37795,8 +37795,8 @@
     source: "ch15/15.3/15.3.4/15.3.4.5/15.3.4.5-15-1.js"
   },
   {
-    skip: false,
-    reason: "",
+    skip: true,
+    reason: "the spec has changed",
     source: "ch15/15.3/15.3.4/15.3.4.5/15.3.4.5-15-2.js"
   },
   {
@@ -37905,8 +37905,8 @@
     source: "ch15/15.3/15.3.4/15.3.4.5/15.3.4.5-2-9.js"
   },
   {
-    skip: false,
-    reason: "",
+    skip: true,
+    reason: "function no longer has caller present",
     source: "ch15/15.3/15.3.4/15.3.4.5/15.3.4.5-20-1.js"
   },
   {
@@ -37920,18 +37920,18 @@
     source: "ch15/15.3/15.3.4/15.3.4.5/15.3.4.5-20-3.js"
   },
   {
-    skip: false,
-    reason: "",
+    skip: true,
+    reason: "function no longer has caller present",
     source: "ch15/15.3/15.3.4/15.3.4.5/15.3.4.5-20-4.js"
   },
   {
-    skip: false,
-    reason: "",
+    skip: true,
+    reason: "function no longer has caller present",
     source: "ch15/15.3/15.3.4/15.3.4.5/15.3.4.5-20-5.js"
   },
   {
-    skip: false,
-    reason: "",
+    skip: true,
+    reason: "bind no longer has arguments",
     source: "ch15/15.3/15.3.4/15.3.4.5/15.3.4.5-21-1.js"
   },
   {
@@ -37945,13 +37945,13 @@
     source: "ch15/15.3/15.3.4/15.3.4.5/15.3.4.5-21-3.js"
   },
   {
-    skip: false,
-    reason: "",
+    skip: true,
+    reason: "bind no longer has arguments",
     source: "ch15/15.3/15.3.4/15.3.4.5/15.3.4.5-21-4.js"
   },
   {
-    skip: false,
-    reason: "",
+    skip: true,
+    reason: "bind no longer has arguments",
     source: "ch15/15.3/15.3.4/15.3.4.5/15.3.4.5-21-5.js"
   },
   {

+ 15 - 0
Jint.Tests.Test262/BuiltIns/FunctionTests.cs

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

+ 2 - 2
Jint.Tests.Test262/Jint.Tests.Test262.csproj

@@ -6,11 +6,11 @@
     <ProjectReference Include="..\Jint\Jint.csproj" />
   </ItemGroup>
   <ItemGroup>
-    <PackageReference Include="Microsoft.NET.Test.Sdk" Version="16.5.0" />
+    <PackageReference Include="Microsoft.NET.Test.Sdk" Version="16.7.1" />
     <PackageReference Include="Newtonsoft.Json" Version="12.0.3" />
     <PackageReference Include="xunit" Version="2.4.1" />
     <PackageReference Include="xunit.analyzers" Version="0.10.0" />
-    <PackageReference Include="xunit.runner.visualstudio" Version="2.4.1" />
+    <PackageReference Include="xunit.runner.visualstudio" Version="2.4.3" />
     <PackageReference Include="xunit.runner.console" Version="2.4.1" />
     <DotNetCliToolReference Include="dotnet-xunit" Version="2.3.1" />
   </ItemGroup>

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

@@ -52,7 +52,10 @@ namespace Jint.Tests.Test262
                 "assertRelativeDateMs.js",
                 "regExpUtils.js",
                 "nans.js",
-                "compareIterator.js"
+                "compareIterator.js",
+                "nativeFunctionMatcher.js",
+                "wellKnownIntrinsicObjects.js",
+                "fnGlobalObject.js"
             };
 
             Sources = new Dictionary<string, string>(files.Length);

+ 42 - 342
Jint.Tests.Test262/test/skipped.json

@@ -33,6 +33,12 @@
   },
 
 
+  {
+    "source": "built-ins/Function/prototype/toString/method-computed-property-name.js",
+    "reason": "requires investigation how to process complex function name evaluation for property"
+  },
+
+
   // http://www.ecma-international.org/ecma-262/#sec-block-level-function-declarations-web-legacy-compatibility-semantics
   {
     "source": "language/statements/let/block-local-closure-set-before-initialization.js",
@@ -290,138 +296,6 @@
     "source": "built-ins/StringIteratorPrototype/next/next-iteration-surrogate-pairs.js",
     "reason": "code point iteration not implemented"
   },
-  {
-    "source": "built-ins/Date/prototype/toTimeString/format.js",
-    "reason": "let/const not implemented"
-  },
-  {
-    "source": "built-ins/Date/prototype/toString/format.js",
-    "reason": "let/const not implemented"
-  },
-  {
-    "source": "built-ins/Date/parse/zero.js",
-    "reason": "let/const not implemented"
-  },
-  {
-    "source": "built-ins/Date/prototype/toUTCString/format.js",
-    "reason": "let/const not implemented"
-  },
-  {
-    "source": "built-ins/Date/prototype/toDateString/format.js",
-    "reason": "let/const not implemented"
-  },
-  {
-    "source": "language/statements/for-in/head-const-bound-names-fordecl-tdz.js",
-    "reason": "let/const not implemented"
-  },
-  {
-    "source": "language/statements/for-in/head-const-fresh-binding-per-iteration.js",
-    "reason": "let/const not implemented"
-  },
-  {
-    "source": "language/statements/for-in/head-decl-expr.js",
-    "reason": "let/const not implemented"
-  },
-  {
-    "source": "language/statements/for-in/head-let-bound-names-fordecl-tdz.js",
-    "reason": "let/const not implemented"
-  },
-  {
-    "source": "language/statements/for-in/head-let-destructuring.js",
-    "reason": "let/const not implemented"
-  },
-  {
-    "source": "language/statements/for-in/head-let-fresh-binding-per-iteration.js",
-    "reason": "let/const not implemented"
-  },
-  {
-    "source": "language/statements/for-in/head-lhs-let.js",
-    "reason": "let/const not implemented"
-  },
-  {
-    "source": "language/statements/for-in/scope-head-var-none.js",
-    "reason": "let/const not implemented"
-  },
-  {
-    "source": "language/statements/for/head-const-fresh-binding-per-iteration.js",
-    "reason": "let/const not implemented"
-  },
-  {
-    "source": "language/statements/for/head-let-destructuring.js",
-    "reason": "let/const not implemented"
-  },
-  {
-    "source": "language/statements/for/head-let-fresh-binding-per-iteration.js",
-    "reason": "let/const not implemented"
-  },
-  {
-    "source": "built-ins/Symbol/prototype/description/description-symboldescriptivestring.js",
-    "reason": "let/const not implemented"
-  },
-  {
-    "source": "built-ins/Symbol/prototype/description/get.js",
-    "reason": "let/const not implemented"
-  },
-  {
-    "source": "built-ins/Symbol/prototype/description/this-val-non-symbol.js",
-    "reason": "let/const not implemented"
-  },
-  {
-    "source": "built-ins/Symbol/prototype/description/this-val-symbol.js",
-    "reason": "let/const not implemented"
-  },
-  {
-    "source": "built-ins/Symbol/prototype/description/wrapper.js",
-    "reason": "let/const not implemented"
-  },
-  {
-    "source": "language/statements/for-in/head-var-bound-names-dup.js",
-    "reason": "destructing not implemented"
-  },
-  {
-    "source": "built-ins/Math/pow/int32_min-exponent.js",
-    "reason": "const not implemented"
-  },
-  {
-    "source": "language/expressions/assignment/dstr-obj-rest-put-const.js",
-    "reason": "const not implemented"
-  },
-  {
-    "source": "language/statements/for-of/dstr-obj-rest-put-const.js",
-    "reason": "const not implemented"
-  },
-  {
-    "source": "language/statements/for-of/head-const-bound-names-fordecl-tdz.js",
-    "reason": "const not implemented"
-  },
-  {
-    "source": "language/statements/for-of/head-const-fresh-binding-per-iteration.js",
-    "reason": "const not implemented"
-  },
-  {
-    "source": "language/statements/for-of/dstr-const-ary-ptrn-rest-obj-prop-id.js",
-    "reason": "const not implemented"
-  },
-  {
-    "source": "language/statements/for-of/head-let-bound-names-fordecl-tdz.js",
-    "reason": "let not implemented"
-  },
-  {
-    "source": "language/statements/for-of/head-let-destructuring.js",
-    "reason": "let not implemented"
-  },
-  {
-    "source": "language/statements/for-of/head-let-fresh-binding-per-iteration.js",
-    "reason": "let not implemented"
-  },
-  {
-    "source": "language/statements/for-of/dstr-let-ary-ptrn-rest-obj-prop-id.js",
-    "reason": "let not implemented"
-  },
-  {
-    "source": "language/statements/for-of/dstr-var-ary-ptrn-rest-obj-prop-id.js",
-    "reason": "let not implemented"
-  },
   {
     "source": "language/expressions/template-literal/tv-line-terminator-sequence.js",
     "reason": "Line feed problems (git, windows, linux)"
@@ -445,249 +319,75 @@
     "reason": "inner binding rejects modification (from parameters) Expected a Error to be thrown but no exception was thrown at all"
   },
 
-  // let support
-  {
-    "source": "language/expressions/assignment/dstr-array-rest-nested-obj-undefined-own.js",
-    "reason": "let not implemented"
-  },
-  {
-    "source": "language/expressions/assignment/dstr-array-rest-nested-obj-undefined.js",
-    "reason": "let not implemented"
-  },
-  {
-    "source": "language/expressions/assignment/dstr-array-rest-nested-obj-undefined-hole.js",
-    "reason": "let not implemented"
-  },
-  {
-    "source": "language/statements/for/dstr-const-ary-ptrn-rest-obj-prop-id.js",
-    "reason": "let not implemented"
-  },
-  {
-    "source": "language/statements/for/dstr-var-ary-ptrn-rest-obj-prop-id.js",
-    "reason": "let not implemented"
-  },
-  {
-    "source": "language/statements/for/dstr-let-ary-ptrn-rest-obj-prop-id.js",
-    "reason": "let not implemented"
-  },
-  {
-    "source": "language/expressions/arrow-function/dstr-ary-ptrn-elem-id-init-fn-name-cover.js",
-    "mode": "strict",
-    "reason": "let not implemented"
-  },
-  {
-    "source": "language/expressions/arrow-function/dstr-ary-ptrn-rest-obj-prop-id.js",
-    "mode": "strict",
-    "reason": "let not implemented"
-  },
-  {
-    "source": "language/expressions/arrow-function/dstr-dflt-ary-ptrn-rest-obj-prop-id.js",
-    "mode": "strict",
-    "reason": "let not implemented"
-  },
-  {
-    "source": "language/expressions/function/dstr-ary-ptrn-rest-obj-prop-id.js",
-    "mode": "strict",
-    "reason": "let not implemented"
-  },
-  {
-    "source": "language/expressions/function/dstr-dflt-ary-ptrn-rest-obj-prop-id.js",
-    "mode": "strict",
-    "reason": "let not implemented"
-  },
-  {
-    "source": "language/expressions/object/dstr-meth-ary-ptrn-rest-obj-prop-id.js",
-    "mode": "strict",
-    "reason": "let not implemented"
-  },
-  {
-    "source": "language/expressions/object/dstr-meth-dflt-ary-ptrn-rest-obj-prop-id.js",
-    "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"
-  },
+  // class support
   {
-    "source": "language/expressions/new/spread-sngl-obj-ident.js",
-    "mode": "strict",
-    "reason": "let not implemented"
+    "source": "built-ins/Function/prototype/toString/class-declaration-complex-heritage.js",
+    "reason": "class not implemented"
   },
   {
-    "source": "language/expressions/array/spread-mult-obj-ident.js",
-    "mode": "strict",
-    "reason": "let not implemented"
+    "source": "built-ins/Function/prototype/toString/class-declaration-explicit-ctor.js",
+    "reason": "class not implemented"
   },
   {
-    "source": "language/expressions/array/spread-obj-getter-descriptor.js",
-    "mode": "strict",
-    "reason": "let not implemented"
+    "source": "built-ins/Function/prototype/toString/class-declaration-implicit-ctor.js",
+    "reason": "class not implemented"
   },
   {
-    "source": "language/expressions/array/spread-obj-getter-init.js",
-    "mode": "strict",
-    "reason": "let not implemented"
+    "source": "built-ins/Function/prototype/toString/class-expression-explicit-ctor.js",
+    "reason": "class not implemented"
   },
   {
-    "source": "language/expressions/array/spread-obj-mult-spread-getter.js",
-    "mode": "strict",
-    "reason": "let not implemented"
+    "source": "built-ins/Function/prototype/toString/class-expression-implicit-ctor.js",
+    "reason": "class not implemented"
   },
   {
-    "source": "language/expressions/array/spread-obj-mult-spread.js",
-    "mode": "strict",
-    "reason": "let not implemented"
+    "source": "built-ins/Function/prototype/toString/getter-class-expression-static.js",
+    "reason": "class not implemented"
   },
   {
-    "source": "language/expressions/array/spread-obj-override-immutable.js",
-    "mode": "strict",
-    "reason": "let not implemented"
+    "source": "built-ins/Function/prototype/toString/getter-class-expression.js",
+    "reason": "class not implemented"
   },
   {
-    "source": "language/expressions/array/spread-obj-overrides-prev-properties.js",
-    "mode": "strict",
-    "reason": "let not implemented"
+    "source": "built-ins/Function/prototype/toString/getter-class-statement-static.js",
+    "reason": "class not implemented"
   },
   {
-    "source": "language/expressions/array/spread-obj-skip-non-enumerable.js",
-    "mode": "strict",
-    "reason": "let not implemented"
-  },
+    "source": "built-ins/Function/prototype/toString/getter-class-statement.js",
+    "reason": "class not implemented"
+  }, 
   {
-    "source": "language/expressions/array/spread-obj-with-overrides.js",
-    "mode": "strict",
-    "reason": "let not implemented"
+    "source": "built-ins/Function/prototype/toString/method-class-expression-static.js",
+    "reason": "class not implemented"
   },
   {
-    "source": "language/expressions/array/spread-sngl-obj-ident.js",
-    "mode": "strict",
-    "reason": "let not implemented"
+    "source": "built-ins/Function/prototype/toString/method-class-expression.js",
+    "reason": "class not implemented"
   },
   {
-    "source": "language/expressions/array/spread-obj-symbol-property.js",
-    "mode": "strict",
-    "reason": "let not implemented"
+    "source": "built-ins/Function/prototype/toString/method-class-statement-static.js",
+    "reason": "class not implemented"
   },
   {
-    "source": "language/expressions/new/spread-obj-symbol-property.js",
-    "mode": "strict",
-    "reason": "let not implemented"
+    "source": "built-ins/Function/prototype/toString/method-class-statement.js",
+    "reason": "class not implemented"
   },
   {
-    "source": "language/expressions/call/spread-obj-symbol-property.js",
-    "mode": "strict",
-    "reason": "let not implemented"
+    "source": "built-ins/Function/prototype/toString/setter-class-expression-static.js",
+    "reason": "class not implemented"
   },
   {
-    "source": "built-ins/Object/entries/tamper-with-global-object.js",
-    "mode": "strict",
-    "reason": "let not implemented"
+    "source": "built-ins/Function/prototype/toString/setter-class-expression.js",
+    "reason": "class not implemented"
   },
   {
-    "source": "built-ins/Object/values/tamper-with-global-object.js",
-    "mode": "strict",
-    "reason": "let not implemented"
+    "source": "built-ins/Function/prototype/toString/setter-class-statement-static.js",
+    "reason": "class not implemented"
   },
   {
-    "source": "built-ins/Object/keys/proxy-keys.js",
-    "mode": "strict",
-    "reason": "let not implemented"
+    "source": "built-ins/Function/prototype/toString/setter-class-statement.js",
+    "reason": "class not implemented"
   },
-
-
-  // class support
   {
     "source": "language/global-code/script-decl-lex.js",
     "reason": "class not implemented"

+ 5 - 2
Jint.Tests/Jint.Tests.csproj

@@ -1,6 +1,8 @@
 <Project Sdk="Microsoft.NET.Sdk">
   <PropertyGroup>
     <TargetFrameworks>net461;netcoreapp3.1</TargetFrameworks>
+    <AssemblyOriginatorKeyFile>..\Jint\Jint.snk</AssemblyOriginatorKeyFile>
+    <SignAssembly>true</SignAssembly>
   </PropertyGroup>
   <ItemGroup>
     <EmbeddedResource Include="Runtime\Scripts\*.*;Parser\Scripts\*.*" />
@@ -12,10 +14,11 @@
     <Reference Include="Microsoft.CSharp" Condition=" '$(TargetFramework)' == 'net461' " />
   </ItemGroup>
   <ItemGroup>
-    <PackageReference Include="Microsoft.NET.Test.Sdk" Version="16.5.0" />
+    <PackageReference Include="Microsoft.NET.Test.Sdk" Version="16.7.1" />
+    <PackageReference Include="Newtonsoft.Json" Version="12.0.3" />
     <PackageReference Include="xunit" Version="2.4.1" />
     <PackageReference Include="xunit.analyzers" Version="0.10.0" />
-    <PackageReference Include="xunit.runner.visualstudio" Version="2.4.1" />
+    <PackageReference Include="xunit.runner.visualstudio" Version="2.4.3" />
     <PackageReference Include="xunit.runner.console" Version="2.4.1" />
     <DotNetCliToolReference Include="dotnet-xunit" Version="2.3.1" />
   </ItemGroup>

+ 22 - 0
Jint.Tests/Runtime/ArrayTests.cs

@@ -1,4 +1,5 @@
 using System;
+using Jint.Native.Array;
 using Xunit;
 
 namespace Jint.Tests.Runtime
@@ -52,5 +53,26 @@ namespace Jint.Tests.Runtime
 
             Assert.Equal(8, result);
         }
+
+        [Fact]
+        public void LargeArraySize()
+        {
+            const string code = @"
+            let arr = [];
+            for (let i = 0; i < 10000; i++) arr.push(i);
+            for (let i=0;i<10000;i++) arr.splice(0, 1);
+            ";
+            var engine = new Engine();
+            engine.Execute(code);
+        }
+
+        [Fact]
+        public void ArrayLengthFromInitialState()
+        {
+            var engine = new Engine();
+            var array = new ArrayInstance(engine, 0);
+            var length = (int) array.Length;
+            Assert.Equal(0, length);
+        }
     }
 }

+ 43 - 0
Jint.Tests/Runtime/ConstTests.cs

@@ -0,0 +1,43 @@
+using System;
+using Xunit;
+
+namespace Jint.Tests.Runtime
+{
+    public class ConstTests
+    {
+        private readonly Engine _engine;
+
+        public ConstTests()
+        {
+            _engine = new Engine()
+                .SetValue("log", new Action<object>(Console.WriteLine))
+                .SetValue("assert", new Action<bool>(Assert.True))
+                .SetValue("equal", new Action<object, object>(Assert.Equal));
+        }
+
+        [Fact]
+        public void ConstInsideIife()
+        {
+            _engine.Execute(@"
+                (function(){
+                    const testVariable = 'test';
+                    function render() {
+                        log(testVariable);
+                    }
+                    render();
+                })();
+            ");
+        }
+
+        [Fact]
+        public void ConstDestructuring()
+        {
+            _engine.Execute(@"
+                let obj = {};
+                for (var i = 0; i < 1; i++) {
+                    const { subElement } = obj;
+                }
+            ");
+        }
+    }
+}

+ 6 - 0
Jint.Tests/Runtime/DateTests.cs

@@ -57,5 +57,11 @@ namespace Jint.Tests.Runtime
             Assert.Equal("Invalid Date", value);
         }
 
+        [Fact]
+        public void ToJsonFromNaNObject()
+        {
+            var result = _engine.Execute("JSON.stringify({ date: new Date(NaN) });").GetCompletionValue();
+            Assert.Equal("{\"date\":null}", result.ToString());
+        }
     }
 }

+ 12 - 6
Jint.Tests/Runtime/Domain/Company.cs

@@ -6,7 +6,11 @@ namespace Jint.Tests.Runtime.Domain
     public class Company : ICompany, IComparable<ICompany>
     {
         private string _name;
-        private readonly Dictionary<string, string> _dictionary = new Dictionary<string, string>();
+
+        private readonly Dictionary<string, string> _dictionary = new Dictionary<string, string>()
+        {
+            {"key", "value"}
+        };
 
         public Company(string name)
         {
@@ -15,19 +19,21 @@ namespace Jint.Tests.Runtime.Domain
 
         string ICompany.Name
         {
-            get { return _name; }
-            set { _name = value; }
+            get => _name;
+            set => _name = value;
         }
 
         string ICompany.this[string key]
         {
-            get { return _dictionary[key]; }
-            set { _dictionary[key] = value; }
+            get => _dictionary[key];
+            set => _dictionary[key] = value;
         }
 
+        public string Item => "item thingie";
+
         int IComparable<ICompany>.CompareTo(ICompany other)
         {
             return string.Compare(_name, other.Name, StringComparison.CurrentCulture);
         }
     }
-}
+}

+ 16 - 0
Jint.Tests/Runtime/Domain/HiddenMembers.cs

@@ -0,0 +1,16 @@
+namespace Jint.Tests.Runtime.Domain
+{
+    public class HiddenMembers
+    {
+        public string Member1 { get; set; } = "Member1";
+        public string Member2 { get; set; } = "Member2";
+        public string Method1()
+        {
+            return "Method1";
+        }
+        public string Method2()
+        {
+            return "Method2";
+        }
+    }
+}

+ 18 - 0
Jint.Tests/Runtime/Domain/IntegerIndexer.cs

@@ -0,0 +1,18 @@
+namespace Jint.Tests.Runtime.Domain
+{
+    public class IntegerIndexer
+    {
+        private readonly int[] data;
+
+        public IntegerIndexer()
+        {
+            data = new[] {123, 0, 0, 0, 0};
+        }
+
+        public int this[int i]
+        {
+            get => data[i];
+            set => data[i] = value;
+        }
+    }
+}

+ 25 - 0
Jint.Tests/Runtime/Domain/JsUuid.cs

@@ -0,0 +1,25 @@
+using System;
+using Jint.Native;
+
+namespace Jint.Tests.Runtime.Domain
+{
+    public sealed class JsUuid : JsValue, IEquatable<JsUuid>
+    {
+        internal readonly Guid _value;
+        public static readonly JsUuid Empty = new JsUuid(Guid.Empty);
+
+        public JsUuid(Guid value) : base(Jint.Runtime.Types.String) => _value = value;
+
+        public static implicit operator JsUuid(Guid g) => new JsUuid(g);
+
+        public override bool Equals(JsValue other) => Equals(other as JsUuid);
+
+        public bool Equals(JsUuid other) => other?._value == _value;
+
+        public override int GetHashCode() => _value.GetHashCode();
+
+        public override object ToObject() => _value;
+
+        public override string ToString() => _value.ToString();
+    }
+}

+ 70 - 0
Jint.Tests/Runtime/Domain/UuidConstructor.cs

@@ -0,0 +1,70 @@
+using System;
+using Jint.Native;
+using Jint.Native.Function;
+using Jint.Native.Object;
+using Jint.Runtime;
+using Jint.Runtime.Descriptors;
+using Jint.Runtime.Interop;
+
+namespace Jint.Tests.Runtime.Domain
+{
+    internal sealed class UuidConstructor : FunctionInstance, IConstructor
+    {
+        private static readonly JsString _functionName = new JsString("Uuid");
+
+        private UuidConstructor(Engine engine) : base(engine, _functionName)
+        {
+        }
+
+        private JsValue Parse(JsValue @this, JsValue[] arguments)
+        {
+            switch (arguments.At(0))
+            {
+                case JsUuid uid:
+                    return Construct(uid);
+
+                case JsValue js when Guid.TryParse(js.AsString(), out var res):
+                    return Construct(res);
+            }
+
+            return Undefined;
+        }
+
+        protected override ObjectInstance GetPrototypeOf() => _prototype;
+
+        internal ObjectInstance _prototype;
+
+        public UuidPrototype PrototypeObject { get; private set; }
+
+        public static UuidConstructor CreateUuidConstructor(Engine engine)
+        {
+            var obj = new UuidConstructor(engine)
+            {
+                // The value of the [[Prototype]] internal property of the Uuid constructor is the Function prototype object
+                _prototype = engine.Function.PrototypeObject
+            };
+            obj.PrototypeObject = UuidPrototype.CreatePrototypeObject(engine, obj);
+
+            // The initial value of Uuid.prototype is the Date prototype object
+            obj.SetOwnProperty("prototype", new PropertyDescriptor(obj.PrototypeObject, false, false, false));
+
+            engine.SetValue("Uuid", obj);
+            obj.Configure();
+            obj.PrototypeObject.Configure();
+
+            return obj;
+        }
+
+        public override JsValue Call(JsValue thisObject, JsValue[] arguments) => Construct(arguments, null);
+
+        public void Configure()
+        {
+            FastAddProperty("parse", new ClrFunctionInstance(Engine, "parse", Parse), true, false, true);
+            FastAddProperty("Empty", JsUuid.Empty, true, false, true);
+        }
+
+        public UuidInstance Construct(JsUuid uuid) => new UuidInstance(Engine) { PrimitiveValue = uuid, _prototype = PrototypeObject };
+
+        public ObjectInstance Construct(JsValue[] arguments, JsValue newTarget) => Construct(Guid.NewGuid());
+    }
+}

+ 26 - 0
Jint.Tests/Runtime/Domain/UuidConverter.cs

@@ -0,0 +1,26 @@
+using Jint.Native;
+using Jint.Runtime.Interop;
+using System;
+
+namespace Jint.Tests.Runtime.Domain
+{
+    public class UuidConverter : IObjectConverter
+    {
+        internal UuidConverter()
+        {
+        }
+
+        public bool TryConvert(Engine engine, object value, out JsValue result)
+        {
+            switch (value)
+            {
+                case Guid g:
+                    result = new JsUuid(g);
+                    return true;
+            }
+
+            result = JsValue.Undefined;
+            return false;
+        }
+    }
+}

+ 20 - 0
Jint.Tests/Runtime/Domain/UuidInstance.cs

@@ -0,0 +1,20 @@
+using Jint.Native.Object;
+using Jint.Runtime.Interop;
+
+namespace Jint.Tests.Runtime.Domain
+{
+    internal class UuidInstance : ObjectInstance, IObjectWrapper
+    {
+        protected override ObjectInstance GetPrototypeOf() => _prototype;
+
+        internal ObjectInstance _prototype;
+
+        public JsUuid PrimitiveValue { get; set; }
+
+        public object Target => PrimitiveValue?._value;
+
+        public UuidInstance(Engine engine) : base(engine)
+        {
+        }
+    }
+}

+ 44 - 0
Jint.Tests/Runtime/Domain/UuidPrototype.cs

@@ -0,0 +1,44 @@
+using Jint.Native;
+using Jint.Runtime;
+using Jint.Runtime.Interop;
+
+namespace Jint.Tests.Runtime.Domain
+{
+    internal sealed class UuidPrototype : UuidInstance
+    {
+        private UuidPrototype(Engine engine) : base(engine)
+        {
+        }
+
+        private UuidInstance EnsureUuidInstance(JsValue thisObj)
+        {
+            return thisObj.TryCast<UuidInstance>(value =>
+            {
+                throw new JavaScriptException(Engine.TypeError, "Invalid Uuid");
+            });
+        }
+
+        private JsValue ToGuidString(JsValue thisObj, JsValue[] arguments) => EnsureUuidInstance(thisObj).PrimitiveValue.ToString();
+
+        private JsValue ValueOf(JsValue thisObj, JsValue[] arguments) => EnsureUuidInstance(thisObj).PrimitiveValue;
+
+        public static UuidPrototype CreatePrototypeObject(Engine engine, UuidConstructor ctor)
+        {
+            var obj = new UuidPrototype(engine)
+            {
+                PrimitiveValue = JsUuid.Empty,
+                _prototype = engine.Object.PrototypeObject,
+            };
+
+            obj.FastAddProperty("constructor", ctor, false, false, true);
+
+            return obj;
+        }
+
+        public void Configure()
+        {
+            FastAddProperty("toString", new ClrFunctionInstance(Engine, "toString", ToGuidString), true, false, true);
+            FastAddProperty("valueOf", new ClrFunctionInstance(Engine, "valueOf", ValueOf), true, false, true);
+        }
+    }
+}

+ 73 - 7
Jint.Tests/Runtime/EngineTests.cs

@@ -2,6 +2,7 @@
 using System.Globalization;
 using System.IO;
 using System.Reflection;
+using System.Threading;
 using Esprima;
 using Esprima.Ast;
 using Jint.Native;
@@ -738,6 +739,40 @@ namespace Jint.Tests.Runtime
             );
         }
 
+        [Fact]
+        public void ShouldThrowExecutionCanceled()
+        {
+            Assert.Throws<ExecutionCanceledException>(
+                () =>
+                {
+                    using (var tcs = new CancellationTokenSource())
+                    using (var waitHandle = new ManualResetEvent(false))
+                    {
+                        var engine = new Engine(cfg => cfg.CancellationToken(tcs.Token));
+
+                        ThreadPool.QueueUserWorkItem(state =>
+                        {
+                            waitHandle.WaitOne();
+                            tcs.Cancel();
+                        });
+
+                        engine.SetValue("waitHandle", waitHandle);
+                        engine.Execute(@"
+                            function sleep(millisecondsTimeout) {
+                                var totalMilliseconds = new Date().getTime() + millisecondsTimeout;
+
+                                while (new Date() < totalMilliseconds) { }
+                            }
+
+                            sleep(100);
+                            waitHandle.Set();
+                            sleep(5000);
+                        ");
+                    }
+                }
+            );
+        }
+
 
         [Fact]
         public void CanDiscardRecursion()
@@ -990,7 +1025,7 @@ namespace Jint.Tests.Runtime
 
             var x = _engine.GetValue("x");
 
-            Assert.Throws<ArgumentException>(() => x.Invoke(1, 2));
+            Assert.Throws<TypeErrorException>(() => x.Invoke(1, 2));
         }
 
         [Fact]
@@ -1016,7 +1051,7 @@ namespace Jint.Tests.Runtime
             var obj = _engine.GetValue("obj").AsObject();
             var foo = obj.Get("foo", obj);
 
-            Assert.Throws<ArgumentException>(() => _engine.Invoke(foo, obj, new object[] { }));
+            Assert.Throws<JavaScriptException>(() => _engine.Invoke(foo, obj, new object[] { }));
         }
 
         [Fact]
@@ -2810,10 +2845,9 @@ x.test = {
         [Fact]
         public void ShouldOverrideDefaultTypeConverter()
         {
-            var engine = new Engine
-            {
-                ClrTypeConverter = new TestTypeConverter()
-            };
+            var engine = new Engine(options => options
+                .SetTypeConverter(e => new TestTypeConverter())
+            );
             Assert.IsType<TestTypeConverter>(engine.ClrTypeConverter);
             engine.SetValue("x", new Testificate());
             Assert.Throws<JavaScriptException>(() => engine.Execute("c.Name"));
@@ -2834,6 +2868,31 @@ x.test = {
             _engine.Execute("equal(false, str.hasOwnProperty('foo'));");
         }
 
+        [Fact]
+        public void ShouldProvideEngineForOptionsAsOverload()
+        {
+            new Engine((e, options) =>
+                {
+                    Assert.IsType<Engine>(e);
+                    options
+                        .AddObjectConverter(new TestObjectConverter())
+                        .AddObjectConverter<TestObjectConverter>();
+                })
+                .SetValue("a", 1);
+        }
+
+        [Fact]
+        public void ShouldReuseOptions()
+        {
+            var options = new Options().Configure(e => e.SetValue("x", 1));
+
+            var engine1 = new Engine(options);
+            var engine2 = new Engine(options);
+
+            Assert.Equal(1, Convert.ToInt32(engine1.GetValue("x").ToObject()));
+            Assert.Equal(1, Convert.ToInt32(engine2.GetValue("x").ToObject()));
+        }
+
         private class Wrapper
         {
             public Testificate Test { get; set; }
@@ -2845,9 +2904,16 @@ x.test = {
             public Func<int, int, int> Init { get; set; }
         }
 
-        private class TestTypeConverter : Jint.Runtime.Interop.ITypeConverter
+        private class TestObjectConverter : Jint.Runtime.Interop.IObjectConverter
         {
+            public bool TryConvert(Engine engine, object value, out JsValue result)
+            {
+                throw new NotImplementedException();
+            }
+        }
 
+        private class TestTypeConverter : Jint.Runtime.Interop.ITypeConverter
+        {
             public object Convert(object value, Type type, IFormatProvider formatProvider)
             {
                 throw new NotImplementedException();

+ 4 - 4
Jint.Tests/Runtime/ErrorTests.cs

@@ -19,7 +19,7 @@ var b = a.user.name;
 
             var engine = new Engine();
             var e = Assert.Throws<JavaScriptException>(() => engine.Execute(script));
-            Assert.Equal("user is undefined", e.Message);
+            Assert.Equal("Cannot read property 'name' of undefined", e.Message);
             Assert.Equal(4, e.Location.Start.Line);
             Assert.Equal(8, e.Location.Start.Column);
         }
@@ -40,7 +40,7 @@ var c = a(b().Length);
                 return null;
             }));
             var e = Assert.Throws<JavaScriptException>(() => engine.Execute(script));
-            Assert.Equal("The value is null", e.Message);
+            Assert.Equal("Cannot read property 'Length' of null", e.Message);
             Assert.Equal(2, e.Location.Start.Line);
             Assert.Equal(10, e.Location.Start.Column);
         }
@@ -73,7 +73,7 @@ var b = function(v) {
 }", new ParserOptions("custom.js") { Loc = true });
 
             var e = Assert.Throws<JavaScriptException>(() => engine.Execute("var x = b(7);", new ParserOptions("main.js") { Loc = true } ));
-            Assert.Equal("xxx is undefined", e.Message);
+            Assert.Equal("Cannot read property 'yyy' of undefined", e.Message);
             Assert.Equal(2, e.Location.Start.Line);
             Assert.Equal(8, e.Location.Start.Column);
             Assert.Equal("custom.js", e.Location.Source);
@@ -127,7 +127,7 @@ var b = function(v) {
                 Test.recursive(folder);"
             ));
 
-            Assert.Equal("folderInstance is null", javaScriptException.Message);
+            Assert.Equal("Cannot read property 'Name' of null", javaScriptException.Message);
             Assert.Equal(@" at recursive(folderInstance.parent) @  31:8
  at recursive(folderInstance.parent) @  31:8
  at recursive(folderInstance.parent) @  31:8

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

@@ -8,9 +8,11 @@ using System.Reflection;
 using Jint.Native;
 using Jint.Native.Array;
 using Jint.Native.Object;
+using Jint.Runtime;
 using Jint.Runtime.Interop;
 using Jint.Tests.Runtime.Converters;
 using Jint.Tests.Runtime.Domain;
+using Newtonsoft.Json.Linq;
 using Shapes;
 using Xunit;
 
@@ -55,6 +57,39 @@ namespace Jint.Tests.Runtime
             ");
         }
 
+        [Fact]
+        public void CanAccessMemberNamedItem()
+        {
+            _engine.Execute(@"
+                    function item2(arg) {
+                        return arg.item2
+                    }
+                    function item1(arg) {
+                        return arg.item
+                    }
+                    function item3(arg) {
+                        return arg.Item
+                    }
+            ");
+
+            var argument = new Dictionary<string, object>
+            {
+                {"item2", "item2 value"},
+                {"item", "item value"},
+                {"Item", "Item value"}
+            };
+
+            Assert.Equal("item2 value", _engine.Invoke("item2", argument));
+            Assert.Equal("item value", _engine.Invoke("item1", argument));
+            Assert.Equal("Item value", _engine.Invoke("item3", argument));
+
+            var company = new Company("Acme Ltd");
+            _engine.SetValue("c", company);
+            Assert.Equal("item thingie", _engine.Execute("c.Item").GetCompletionValue());
+            Assert.Equal("item thingie", _engine.Execute("c.item").GetCompletionValue());
+            Assert.Equal("value", _engine.Execute("c['key']").GetCompletionValue());
+        }
+
         [Fact]
         public void DelegatesCanBeSet()
         {
@@ -1073,7 +1108,7 @@ namespace Jint.Tests.Runtime
                 var x= 10;
             ");
 
-            Assert.Throws<ArgumentException>(() => _engine.Invoke("x", 1, 2));
+            Assert.Throws<JavaScriptException>(() => _engine.Invoke("x", 1, 2));
         }
 
         [Fact]
@@ -2032,7 +2067,7 @@ namespace Jint.Tests.Runtime
         }
 
         [Fact]
-        public void ShouldNotResolvetoPrimitiveSymbol()
+        public void ShouldNotResolveToPrimitiveSymbol()
         {
             var engine = new Engine(options => 
                 options.AllowClr(typeof(FloatIndexer).GetTypeInfo().Assembly));
@@ -2078,5 +2113,179 @@ namespace Jint.Tests.Runtime
             engine.SetValue("dictionaryTest", new DictionaryTest());
             engine.Execute("dictionaryTest.test2({ values: { a: 1 } });");
         }
+
+        [Fact]
+        public void ShouldSupportSpreadForDictionary()
+        {
+            var engine = new Engine();
+            var state = new Dictionary<string, object>
+            {
+                {"invoice", new Dictionary<string, object> {["number"] = "42"}}
+            };
+            engine.SetValue("state", state);
+
+            var result = (IDictionary<string, object>) engine
+                .Execute("({ supplier: 'S1', ...state.invoice })")
+                .GetCompletionValue()
+                .ToObject();
+
+            Assert.Equal("S1", result["supplier"]);
+            Assert.Equal("42", result["number"]);            
+        }
+        
+        [Fact]
+        public void ShouldSupportSpreadForDictionary2()
+        {
+            var engine = new Engine();
+            var state = new Dictionary<string, object>
+            {
+                {"invoice", new Dictionary<string, object> {["number"] = "42"}}
+            };
+            engine.SetValue("state", state);
+
+            var result = (IDictionary<string, object>) engine
+                .Execute("function getValue() { return {supplier: 'S1', ...state.invoice}; }")
+                .Invoke("getValue")
+                .ToObject();
+            
+            Assert.Equal("S1", result["supplier"]);
+            Assert.Equal("42", result["number"]);    
+        }        
+
+        [Fact]
+        public void ShouldSupportSpreadForObject()
+        {
+            var engine = new Engine();
+            var person = new Person
+            {
+                Name = "Mike",
+                Age = 20
+            };
+            engine.SetValue("p", person);
+
+            var result = (IDictionary<string, object>) engine
+                .Execute("({ supplier: 'S1', ...p })")
+                .GetCompletionValue()
+                .ToObject();
+
+            Assert.Equal("S1", result["supplier"]);
+            Assert.Equal("Mike", result["Name"]);         
+            Assert.Equal(20d, result["Age"]);         
+        }
+
+        [Fact]
+        public void ShouldBeAbleToJsonStringifyClrObjects()
+        {
+            var engine = new Engine();
+
+            engine.Execute("var jsObj = { 'key1' :'value1', 'key2' : 'value2' }");
+
+            engine.SetValue("netObj", new Dictionary<string, object>
+            {
+                {"key1", "value1"},
+                {"key2", "value2"},
+            });
+
+            var jsValue = engine.Execute("jsObj['key1']").GetCompletionValue().AsString();
+            var clrValue = engine.Execute("netObj['key1']").GetCompletionValue().AsString();
+            Assert.Equal(jsValue, clrValue);
+
+            jsValue = engine.Execute("JSON.stringify(jsObj)").GetCompletionValue().AsString();
+            clrValue = engine.Execute("JSON.stringify(netObj)").GetCompletionValue().AsString();
+            Assert.Equal(jsValue, clrValue);
+
+            // Write properties on screen using showProps function defined on https://developer.mozilla.org/en-US/docs/Web/JavaScript/Guide/Working_with_Objects
+            engine.Execute(@"function showProps(obj, objName) {
+  var result = """";
+  for (var i in obj) {
+    if (obj.hasOwnProperty(i)) {
+      result += objName + ""."" + i + "" = "" + obj[i] + ""\n"";
+    }
+    }
+  return result;
+}");
+            jsValue = engine.Execute("showProps(jsObj, 'theObject')").GetCompletionValue().AsString();
+            clrValue = engine.Execute("showProps(jsObj, 'theObject')").GetCompletionValue().AsString();
+            Assert.Equal(jsValue, clrValue);
+        }
+
+        [Fact]
+        public void ShouldHideSpecificMembers()
+        {
+            var engine = new Engine(options => options.SetMemberAccessor((e, target, member) =>
+            {
+                if (target is HiddenMembers)
+                {
+                    if (member == nameof(HiddenMembers.Member2) || member == nameof(HiddenMembers.Method2))
+                    {
+                        return JsValue.Undefined;
+                    }
+                }
+
+                return null;
+            }));
+
+            engine.SetValue("m", new HiddenMembers());
+
+            Assert.Equal("Member1", engine.Execute("m.Member1").GetCompletionValue().ToString());
+            Assert.Equal("undefined", engine.Execute("m.Member2").GetCompletionValue().ToString());
+            Assert.Equal("Method1", engine.Execute("m.Method1()").GetCompletionValue().ToString());
+            // check the method itself, not its invokation as it would mean invoking "undefined"
+            Assert.Equal("undefined", engine.Execute("m.Method2").GetCompletionValue().ToString());
+        }
+
+        [Fact]
+        public void ShouldOverrideMembers()
+        {
+            var engine = new Engine(options => options.SetMemberAccessor((e, target, member) =>
+            {
+                if (target is HiddenMembers && member == nameof(HiddenMembers.Member1))
+                {
+                    return "Orange";
+                }
+
+                return null;
+            }));
+            
+            engine.SetValue("m", new HiddenMembers());
+
+            Assert.Equal("Orange", engine.Execute("m.Member1").GetCompletionValue().ToString());
+        }
+
+        [Fact]
+        public void SettingValueViaIntegerIndexer()
+        {
+            var engine = new Engine(cfg => cfg.AllowClr(typeof(FloatIndexer).GetTypeInfo().Assembly));
+            engine.SetValue("log", new Action<object>(Console.WriteLine));
+            engine.Execute(@"
+                var domain = importNamespace('Jint.Tests.Runtime.Domain');
+                var fia = new domain.IntegerIndexer();
+                log(fia[0]);
+            ");
+
+            Assert.Equal(123, engine.Execute("fia[0]").GetCompletionValue().AsNumber());
+            engine.Execute("fia[0] = 678;");
+            Assert.Equal(678, engine.Execute("fia[0]").GetCompletionValue().AsNumber());
+        }
+
+        [Fact]
+        public void AccessingJObjectShouldWork()
+        {
+            var o = new JObject
+            {
+                new JProperty("name", "test-name")
+            };
+            _engine.SetValue("o", o);
+            Assert.True(_engine.Execute("return o.name == 'test-name'").GetCompletionValue().AsBoolean());
+        }
+
+        [Fact]
+        public void AccessingJArrayViaIntegerIndexShouldWork()
+        {
+            var o = new JArray("item1", "item2");
+            _engine.SetValue("o", o);
+            Assert.True(_engine.Execute("return o[0] == 'item1'").GetCompletionValue().AsBoolean());
+            Assert.True(_engine.Execute("return o[1] == 'item2'").GetCompletionValue().AsBoolean());
+        }
     }
 }

+ 50 - 0
Jint.Tests/Runtime/UuidTests.cs

@@ -0,0 +1,50 @@
+using Jint.Tests.Runtime.Domain;
+using System;
+using Xunit;
+
+namespace Jint.Tests.Runtime
+{
+    public class UuidTests : IDisposable
+    {
+        private readonly Engine _engine;
+
+        public UuidTests()
+        {
+            _engine = new Engine(o => o.AddObjectConverter(new UuidConverter()))
+                .SetValue("copy", new Func<Guid, Guid>(v => new Guid(v.ToByteArray())))
+                ;
+            UuidConstructor.CreateUuidConstructor(_engine);
+        }
+
+        void IDisposable.Dispose()
+        {
+        }
+
+        private object RunTest(string source)
+        {
+            return _engine.Execute(source).GetCompletionValue().ToObject();
+        }
+
+        [Fact]
+        public void Empty()
+        {
+            Assert.Equal(Guid.Empty, RunTest($"Uuid.parse('{Guid.Empty}')"));
+            Assert.Equal(Guid.Empty, RunTest($"Uuid.Empty"));
+        }
+
+        [Fact]
+        public void Random()
+        {
+            var actual = RunTest($"new Uuid()");
+            Assert.NotEqual(Guid.Empty, actual);
+            Assert.IsType<Guid>(actual);
+        }
+
+        [Fact]
+        public void Copy()
+        {
+            var actual = (bool)RunTest($"const g = new Uuid(); copy(g).toString() === g.toString()");
+            Assert.True(actual);
+        }
+    }
+}

+ 1 - 0
Jint/AssemblyInfoExtras.cs

@@ -1,3 +1,4 @@
 using System.Runtime.CompilerServices;
 
+[assembly: InternalsVisibleTo("Jint.Tests, PublicKey=0024000004800000940000000602000000240000525341310004000001000100bf2553c9f214cb21f1f64ed62cadad8fe4f2fa11322a5dfa1d650743145c6085aba05b145b29867af656e0bb9bfd32f5d0deb1668263a38233e7e8e5bad1a3c6edd3f2ec6c512668b4aa797283101444628650949641b4f7cb16707efba542bb754afe87ce956f3a5d43f450d14364eb9571cbf213d1061852fb9dd47a6c05c4")]
 [assembly: InternalsVisibleTo("Jint.Benchmark, PublicKey=0024000004800000940000000602000000240000525341310004000001000100bf2553c9f214cb21f1f64ed62cadad8fe4f2fa11322a5dfa1d650743145c6085aba05b145b29867af656e0bb9bfd32f5d0deb1668263a38233e7e8e5bad1a3c6edd3f2ec6c512668b4aa797283101444628650949641b4f7cb16707efba542bb754afe87ce956f3a5d43f450d14364eb9571cbf213d1061852fb9dd47a6c05c4")]

+ 1 - 1
Jint/Constraints/CancellationConstraint.cs

@@ -16,7 +16,7 @@ namespace Jint.Constraints
         {
             if (_cancellationToken.IsCancellationRequested)
             {
-                ExceptionHelper.ThrowStatementsCountOverflowException();
+                ExceptionHelper.ThrowExecutionCanceledException();
             }
         }
 

+ 3 - 3
Jint/Directory.Build.props

@@ -10,12 +10,12 @@
     <PackageId>Jint</PackageId>
     <PackageTags>javascript, interpreter</PackageTags>
     <PackageProjectUrl>https://github.com/sebastienros/jint</PackageProjectUrl>
-    <PackageLicenseUrl>https://raw.githubusercontent.com/sebastienros/jint/master/LICENSE.txt</PackageLicenseUrl>
+    <PackageLicenseExpression>BSD-2-Clause</PackageLicenseExpression>
 
-    <!-- SourceLink support -->
     <PublishRepositoryUrl>true</PublishRepositoryUrl>
     <EmbedUntrackedSources>true</EmbedUntrackedSources>
-    <AllowedOutputExtensionsInPackageBuildOutputFolder>$(AllowedOutputExtensionsInPackageBuildOutputFolder);.pdb</AllowedOutputExtensionsInPackageBuildOutputFolder>
+    <IncludeSymbols>true</IncludeSymbols>
+    <SymbolPackageFormat>snupkg</SymbolPackageFormat>
 
   </PropertyGroup>
 

+ 39 - 49
Jint/Engine.cs

@@ -78,7 +78,7 @@ namespace Jint
         internal readonly ArgumentsInstancePool _argumentsInstancePool;
         internal readonly JsValueArrayPool _jsValueArrayPool;
 
-        public ITypeConverter ClrTypeConverter { get; set; }
+        public ITypeConverter ClrTypeConverter { get; internal set; }
 
         // cache of types used when resolving CLR type names
         internal readonly Dictionary<string, Type> TypeCache = new Dictionary<string, Type>();
@@ -105,52 +105,41 @@ namespace Jint
         };
 
         // shared frozen version
-        internal readonly PropertyDescriptor _getSetThrower;
-
-        internal readonly struct ClrPropertyDescriptorFactoriesKey : IEquatable<ClrPropertyDescriptorFactoriesKey>
-        {
-            public ClrPropertyDescriptorFactoriesKey(Type type, Key propertyName)
-            {
-                Type = type;
-                PropertyName = propertyName;
-            }
-
-            private readonly Type Type;
-            private readonly Key PropertyName;
-
-            public bool Equals(ClrPropertyDescriptorFactoriesKey other)
-            {
-                return Type == other.Type && PropertyName == other.PropertyName;
-            }
-
-            public override bool Equals(object obj)
-            {
-                if (ReferenceEquals(null, obj))
-                {
-                    return false;
-                }
-                return obj is ClrPropertyDescriptorFactoriesKey other && Equals(other);
-            }
-
-            public override int GetHashCode()
-            {
-                unchecked
-                {
-                    return (Type.GetHashCode() * 397) ^ PropertyName.GetHashCode();
-                }
-            }
-        }
+        internal readonly PropertyDescriptor _callerCalleeArgumentsThrowerConfigurable;
+        internal readonly PropertyDescriptor _callerCalleeArgumentsThrowerNonConfigurable;
 
         internal readonly Dictionary<ClrPropertyDescriptorFactoriesKey, Func<Engine, object, PropertyDescriptor>> ClrPropertyDescriptorFactories =
             new Dictionary<ClrPropertyDescriptorFactoriesKey, Func<Engine, object, PropertyDescriptor>>();
 
         internal readonly JintCallStack CallStack = new JintCallStack();
 
-        public Engine() : this(null)
+        /// <summary>
+        /// Constructs a new engine instance.
+        /// </summary>
+        public Engine() : this((Action<Options>) null)
         {
         }
 
+        /// <summary>
+        /// Constructs a new engine instance and allows customizing options.
+        /// </summary>
         public Engine(Action<Options> options)
+            : this((engine, opts) => options?.Invoke(opts))
+        {
+        }
+
+        /// <summary>
+        /// Constructs a new engine with a custom <see cref="Options"/> instance.
+        /// </summary>
+        public Engine(Options options) : this((e, o) => e.Options = options)
+        {
+        }
+
+        /// <summary>
+        /// Constructs a new engine instance and allows customizing options.
+        /// </summary>
+        /// <remarks>The provided engine instance in callback is not guaranteed to be fully configured</remarks>
+        public Engine(Action<Engine, Options> options)
         {
             _executionContexts = new ExecutionContextStack(2);
 
@@ -158,7 +147,8 @@ namespace Jint
 
             Object = ObjectConstructor.CreateObjectConstructor(this);
             Function = FunctionConstructor.CreateFunctionConstructor(this);
-            _getSetThrower = new GetSetPropertyDescriptor.ThrowerPropertyDescriptor(Function.ThrowTypeError);
+            _callerCalleeArgumentsThrowerConfigurable = new GetSetPropertyDescriptor.ThrowerPropertyDescriptor(this,  PropertyFlag.Configurable | PropertyFlag.CustomJsValue, "'caller', 'callee', and 'arguments' properties may not be accessed on strict mode functions or the arguments objects for calls to them");
+            _callerCalleeArgumentsThrowerNonConfigurable = new GetSetPropertyDescriptor.ThrowerPropertyDescriptor(this, PropertyFlag.CustomJsValue, "'caller', 'callee', and 'arguments' properties may not be accessed on strict mode functions or the arguments objects for calls to them");
 
             Symbol = SymbolConstructor.CreateSymbolConstructor(this);
             Array = ArrayConstructor.CreateArrayConstructor(this);
@@ -193,9 +183,12 @@ namespace Jint
             // create the global execution context http://www.ecma-international.org/ecma-262/5.1/#sec-10.4.1.1
             EnterExecutionContext(GlobalEnvironment, GlobalEnvironment);
 
+            Eval = new EvalFunctionInstance(this);
+            Global.SetProperty(CommonProperties.Eval, new PropertyDescriptor(Eval, PropertyFlag.Configurable | PropertyFlag.Writable));
+
             Options = new Options();
 
-            options?.Invoke(Options);
+            options?.Invoke(this, Options);
 
             // gather some options as fields for faster checks
             _isDebugMode = Options.IsDebugMode;
@@ -207,9 +200,6 @@ namespace Jint
             _argumentsInstancePool = new ArgumentsInstancePool(this);
             _jsValueArrayPool = new JsValueArrayPool();
 
-            Eval = new EvalFunctionInstance(this);
-            Global.SetProperty(CommonProperties.Eval, new PropertyDescriptor(Eval, PropertyFlag.Configurable | PropertyFlag.Writable));
-
             if (Options._IsClrAllowed)
             {
                 Global.SetProperty("System", new PropertyDescriptor(new NamespaceReference(this, "System"), PropertyFlag.AllForbidden));
@@ -219,7 +209,9 @@ namespace Jint
                     (thisObj, arguments) => new NamespaceReference(this, TypeConverter.ToString(arguments.At(0)))), PropertyFlag.AllForbidden));
             }
 
-            ClrTypeConverter = new DefaultTypeConverter(this);
+            Options.Apply(this);
+
+            ClrTypeConverter ??= new DefaultTypeConverter(this);
         }
 
         internal LexicalEnvironment GlobalEnvironment { get; }
@@ -260,7 +252,7 @@ namespace Jint
 
         internal long CurrentMemoryUsage { get; private set; }
 
-        internal Options Options { [MethodImpl(MethodImplOptions.AggressiveInlining)] get; }
+        internal Options Options { [MethodImpl(MethodImplOptions.AggressiveInlining)] get; private set; }
 
         #region Debugger
         public delegate StepMode DebugStepDelegate(object sender, DebugInformation e);
@@ -450,8 +442,7 @@ namespace Jint
 
             if (baseValue._type == InternalTypes.Undefined)
             {
-                if (_referenceResolver != null &&
-                    _referenceResolver.TryUnresolvableReference(this, reference, out JsValue val))
+                if (_referenceResolver.TryUnresolvableReference(this, reference, out JsValue val))
                 {
                     return val;
                 }
@@ -459,8 +450,7 @@ namespace Jint
                 ExceptionHelper.ThrowReferenceError(this, reference);
             }
 
-            if (_referenceResolver != null
-                && (baseValue._type & InternalTypes.ObjectEnvironmentRecord) == 0
+            if ((baseValue._type & InternalTypes.ObjectEnvironmentRecord) == 0
                 && _referenceResolver.TryPropertyReference(this, reference, ref baseValue))
             {
                 return baseValue;
@@ -656,7 +646,7 @@ namespace Jint
         /// <returns>The value returned by the function call.</returns>
         public JsValue Invoke(JsValue value, object thisObj, object[] arguments)
         {
-            var callable = value as ICallable ?? ExceptionHelper.ThrowArgumentException<ICallable>("Can only invoke functions");
+            var callable = value as ICallable ?? ExceptionHelper.ThrowTypeError<ICallable>(this, "Can only invoke functions");
 
             var items = _jsValueArrayPool.RentArray(arguments.Length);
             for (int i = 0; i < arguments.Length; ++i)

+ 1 - 1
Jint/Jint.csproj

@@ -7,6 +7,6 @@
     <LangVersion>latest</LangVersion>
   </PropertyGroup>
   <ItemGroup>
-    <PackageReference Include="Esprima" Version="2.0.0-beta-1298" />
+    <PackageReference Include="Esprima" Version="2.0.0-beta-1310" />
   </ItemGroup>
 </Project>

+ 1 - 1
Jint/Native/Argument/ArgumentsInstance.cs

@@ -66,7 +66,7 @@ namespace Jint.Native.Argument
                     CreateDataProperty(JsNumber.Create(i), val);
                 }
                 
-                DefinePropertyOrThrow(CommonProperties.Callee, _engine._getSetThrower);
+                DefinePropertyOrThrow(CommonProperties.Callee, _engine._callerCalleeArgumentsThrowerNonConfigurable);
             }
             else
             {

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

@@ -222,6 +222,11 @@ namespace Jint.Native.Array
         [MethodImpl(MethodImplOptions.AggressiveInlining)]
         internal uint GetLength()
         {
+            if (_length is null)
+            {
+                return 0;
+            }
+            
             return (uint) ((JsNumber) _length._value)._value;
         }
 
@@ -648,13 +653,15 @@ namespace Jint.Native.Array
 
         internal void EnsureCapacity(uint capacity)
         {
-            if (capacity <= MaxDenseArrayLength && capacity > (uint) _dense.Length)
+            if (capacity > MaxDenseArrayLength || _dense is null || capacity <= (uint) _dense.Length)
             {
-                // need to grow
-                var newArray = new PropertyDescriptor[capacity];
-                System.Array.Copy(_dense, newArray, _dense.Length);
-                _dense = newArray;
+                return;
             }
+
+            // need to grow
+            var newArray = new PropertyDescriptor[capacity];
+            System.Array.Copy(_dense, newArray, _dense.Length);
+            _dense = newArray;
         }
 
         public IEnumerator<JsValue> GetEnumerator()
@@ -820,6 +827,8 @@ namespace Jint.Native.Array
 
         public override uint Length => GetLength();
 
+        internal override bool IsIntegerIndexedArray => true;
+
         public JsValue this[uint index]
         {
             get

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

@@ -688,7 +688,7 @@ namespace Jint.Native.Date
         {
             var o = TypeConverter.ToObject(Engine, thisObj);
             var tv = TypeConverter.ToPrimitive(o, Types.Number);
-            if (tv.IsNumber() && double.IsInfinity(((JsNumber) tv)._value))
+            if (tv.IsNumber() && !IsFinite(((JsNumber) tv)._value))
             {
                 return Null;
             }

+ 1 - 25
Jint/Native/Function/ArrowFunctionInstance.cs

@@ -1,4 +1,3 @@
-using System.Runtime.CompilerServices;
 using Esprima.Ast;
 using Jint.Runtime;
 using Jint.Runtime.Descriptors;
@@ -60,7 +59,7 @@ namespace Jint.Native.Function
                         arguments,
                         localEnv);
 
-                    var result = _function.Body.Execute();
+                    var result = _function.Execute();
 
                     var value = result.GetValueOrDefault().Clone();
 
@@ -82,28 +81,5 @@ namespace Jint.Native.Function
                 return Undefined;
             }
         }
-
-        public override bool Set(JsValue property, JsValue value, JsValue receiver)
-        {
-            AssertValidPropertyName(property);
-            return base.Set(property, value, receiver);
-        }
-
-        public override JsValue Get(JsValue property, JsValue receiver)
-        {
-            AssertValidPropertyName(property);
-            return base.Get(property, receiver);
-        }
-
-        [MethodImpl(MethodImplOptions.AggressiveInlining)]
-        private void AssertValidPropertyName(JsValue property)
-        {
-            if (property == CommonProperties.Caller
-                || property ==  CommonProperties.Callee
-                || property == CommonProperties.Arguments)
-            {
-                ExceptionHelper.ThrowTypeError(_engine, "'caller', 'callee', and 'arguments' properties may not be accessed on strict mode functions or the arguments objects for calls to them");
-            }
-        }
     }
 }

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

@@ -6,10 +6,8 @@ namespace Jint.Native.Function
 {
     public sealed class BindFunctionInstance : FunctionInstance, IConstructor
     {
-        private static readonly JsString _name = new JsString("bind");
-
-        public BindFunctionInstance(Engine engine)
-            : base(engine, _name, FunctionThisMode.Global)
+        public BindFunctionInstance(Engine engine) 
+            : base(engine, name: null, thisMode: FunctionThisMode.Strict)
         {
         }
 
@@ -55,5 +53,7 @@ namespace Jint.Native.Function
         }
 
         internal override bool IsConstructor => TargetFunction is IConstructor;
+
+        public override string ToString() => "function () { [native code] }";
     }
 }

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

@@ -84,7 +84,7 @@ namespace Jint.Native.Function
                 {
                     Engine.EvalDeclarationInstantiation(script, varEnv, lexEnv, strictEval);
 
-                    var statement = JintStatement.Build(_engine, script);
+                    var statement = new JintScript(_engine, script);
                     var result = statement.Execute();
                     var value = result.GetValueOrDefault();
 

+ 35 - 18
Jint/Native/Function/FunctionConstructor.cs

@@ -11,9 +11,7 @@ namespace Jint.Native.Function
     {
         private static readonly ParserOptions ParserOptions = new ParserOptions { AdaptRegexp = true, Tolerant = false };
         private static readonly JsString _functionName = new JsString("Function");
-
-        private FunctionInstance _throwTypeError;
-        private static readonly char[] ArgumentNameSeparator = new[] { ',' };
+        private static readonly JsString _functionNameAnonymous = new JsString("anonymous");
 
         private FunctionConstructor(Engine engine)
             : base(engine, _functionName)
@@ -71,7 +69,37 @@ namespace Jint.Native.Function
             IFunction function;
             try
             {
-                var functionExpression = "function f(" + p + ") { " + body + "}";
+                string functionExpression;
+                if (argCount == 0)
+                {
+                    functionExpression = "function f(){}";
+                }
+                else
+                {
+                    functionExpression = "function f(";
+                    if (p.IndexOf('/') != -1)
+                    {
+                        // ensure comments don't screw up things
+                        functionExpression += "\n" + p + "\n";
+                    }
+                    else
+                    {
+                        functionExpression += p;
+                    }
+
+                    functionExpression += ")";
+
+                    if (body.IndexOf('/') != -1)
+                    {
+                        // ensure comments don't screw up things
+                        functionExpression += "{\n" + body + "\n}";
+                    }
+                    else
+                    {
+                        functionExpression += "{" + body + "}";
+                    }
+                }
+
                 var parser = new JavaScriptParser(functionExpression, ParserOptions);
                 function = (IFunction) parser.ParseScript().Body[0];
             }
@@ -86,6 +114,9 @@ namespace Jint.Native.Function
                 _engine.GlobalEnvironment,
                 function.Strict);
 
+            // the function is not actually a named function
+            functionObject.SetFunctionName(_functionNameAnonymous, force: true);
+
             return functionObject;
         }
 
@@ -105,20 +136,6 @@ namespace Jint.Native.Function
             return functionObject;
         }
 
-        public FunctionInstance ThrowTypeError
-        {
-            get
-            {
-                if (!ReferenceEquals(_throwTypeError, null))
-                {
-                    return _throwTypeError;
-                }
-
-                _throwTypeError = new ThrowTypeError(Engine);
-                return _throwTypeError;
-            }
-        }
-
         public object Apply(JsValue thisObject, JsValue[] arguments)
         {
             if (arguments.Length != 2)

+ 47 - 49
Jint/Native/Function/FunctionInstance.cs

@@ -19,10 +19,8 @@ namespace Jint.Native.Function
 
         protected internal PropertyDescriptor _prototypeDescriptor;
 
-        protected PropertyDescriptor _length;
-
-        private JsValue _name;
-        private PropertyDescriptor _nameDescriptor;
+        protected internal PropertyDescriptor _length;
+        internal PropertyDescriptor _nameDescriptor;
 
         protected internal LexicalEnvironment _environment;
         internal readonly JintFunctionDefinition _functionDefinition;
@@ -33,7 +31,7 @@ namespace Jint.Native.Function
             JintFunctionDefinition function,
             LexicalEnvironment scope,
             FunctionThisMode thisMode)
-            : this(engine, !string.IsNullOrWhiteSpace(function.Name) ? new JsString(function.Name) : null,  thisMode)
+            : this(engine, !string.IsNullOrWhiteSpace(function.Name) ? new JsString(function.Name) : null, thisMode)
         {
             _functionDefinition = function;
             _environment = scope;
@@ -46,10 +44,20 @@ namespace Jint.Native.Function
             ObjectClass objectClass = ObjectClass.Function)
             : base(engine, objectClass)
         {
-            _name = name;
+            if (!(name is null))
+            {
+                _nameDescriptor = new PropertyDescriptor(name, PropertyFlag.Configurable);
+            }
             _thisMode = thisMode;
         }
 
+        protected FunctionInstance(
+            Engine engine,
+            JsString name)
+            : this(engine, name, FunctionThisMode.Global, ObjectClass.Function)
+        {
+        }
+
         /// <summary>
         /// Executed when a function object is used as a function
         /// </summary>
@@ -59,7 +67,7 @@ namespace Jint.Native.Function
         public abstract JsValue Call(JsValue thisObject, JsValue[] arguments);
 
         public bool Strict => _thisMode == FunctionThisMode.Strict;
-        
+
         public virtual bool HasInstance(JsValue v)
         {
             if (!(v is ObjectInstance o))
@@ -67,7 +75,7 @@ namespace Jint.Native.Function
                 return false;
             }
 
-            var p = Get(CommonProperties.Prototype, this);
+            var p = Get(CommonProperties.Prototype);
             if (!(p is ObjectInstance prototype))
             {
                 ExceptionHelper.ThrowTypeError(_engine, $"Function has non-object prototype '{TypeConverter.ToString(p)}' in instanceof check");
@@ -89,22 +97,6 @@ namespace Jint.Native.Function
             }
         }
 
-        /// <summary>
-        /// http://www.ecma-international.org/ecma-262/5.1/#sec-15.3.5.4
-        /// </summary>
-        public override JsValue Get(JsValue property, JsValue receiver)
-        {
-            var v = base.Get(property, receiver);
-
-            if (property == CommonProperties.Caller
-                && v.As<FunctionInstance>()?._thisMode == FunctionThisMode.Strict)
-            {
-                ExceptionHelper.ThrowTypeError(_engine);
-            }
-
-            return v;
-        }
-
         public override IEnumerable<KeyValuePair<JsValue, PropertyDescriptor>> GetOwnProperties()
         {
             if (_prototypeDescriptor != null)
@@ -115,7 +107,7 @@ namespace Jint.Native.Function
             {
                 yield return new KeyValuePair<JsValue, PropertyDescriptor>(CommonProperties.Length, _length);
             }
-            if (!(_name is null))
+            if (_nameDescriptor != null)
             {
                 yield return new KeyValuePair<JsValue, PropertyDescriptor>(CommonProperties.Name, GetOwnProperty(CommonProperties.Name));
             }
@@ -137,7 +129,7 @@ namespace Jint.Native.Function
             {
                 keys.Add(CommonProperties.Length);
             }
-            if (!(_name is null))
+            if (_nameDescriptor != null)
             {
                 keys.Add(CommonProperties.Name);
             }
@@ -159,9 +151,7 @@ namespace Jint.Native.Function
             }
             if (property == CommonProperties.Name)
             {
-                return !(_name is null)
-                    ? _nameDescriptor ??= new PropertyDescriptor(_name, PropertyFlag.Configurable)
-                    :  PropertyDescriptor.Undefined;
+                return _nameDescriptor ?? PropertyDescriptor.Undefined;
             }
 
             return base.GetOwnProperty(property);
@@ -179,7 +169,6 @@ namespace Jint.Native.Function
             }
             else if (property == CommonProperties.Name)
             {
-                _name = desc._value;
                 _nameDescriptor = desc;
             }
             else
@@ -200,7 +189,7 @@ namespace Jint.Native.Function
             }
             if (property == CommonProperties.Name)
             {
-                return !(_name is null);
+                return _nameDescriptor != null;
             }
 
             return base.HasOwnProperty(property);
@@ -218,34 +207,31 @@ namespace Jint.Native.Function
             }
             if (property == CommonProperties.Name)
             {
-                _name = null;
                 _nameDescriptor = null;
             }
 
             base.RemoveOwnProperty(property);
         }
 
-        internal void SetFunctionName(JsValue name, bool throwIfExists = false)
+        internal void SetFunctionName(JsValue name, string prefix = null, bool force = false)
         {
-            if (_name is null)
+            if (!force && _nameDescriptor != null && !UnwrapJsValue(_nameDescriptor).IsUndefined())
             {
-                JsString value;
-                if (name is JsSymbol symbol)
-                {
-                    value = new JsString(symbol._value.IsUndefined()
-                        ? ""
-                        : "[" + symbol._value + "]");
-                }
-                else
-                {
-                    value = name as JsString ?? new JsString(name.ToString());
-                }
-                _name = value;
+                return;
             }
-            else if (throwIfExists)
+
+            if (name is JsSymbol symbol)
             {
-                ExceptionHelper.ThrowError(_engine, "cannot set name");
+                name = symbol._value.IsUndefined()
+                    ? JsString.Empty
+                    : new JsString("[" + symbol._value + "]");
             }
+            if (!string.IsNullOrWhiteSpace(prefix))
+            {
+                name = prefix + " " + name;
+            }
+
+            _nameDescriptor = new PropertyDescriptor(name, PropertyFlag.Configurable);
         }
 
         [MethodImpl(MethodImplOptions.AggressiveInlining)]
@@ -269,5 +255,17 @@ namespace Jint.Native.Function
             //    Set proto to realm's intrinsic object named intrinsicDefaultProto.
             return proto ?? intrinsicDefaultProto;
         }
+
+        public override string ToString()
+        {
+            // TODO no way to extract SourceText from Esprima at the moment, just returning native code
+            var nameValue = _nameDescriptor != null ? UnwrapJsValue(_nameDescriptor) : JsString.Empty;
+            var name = "";
+            if (!nameValue.IsUndefined())
+            {
+                name = TypeConverter.ToString(nameValue);
+            }
+            return "function " + name + "() {{[native code]}}";
+        }
     }
-}
+}

+ 60 - 22
Jint/Native/Function/FunctionPrototype.cs

@@ -1,6 +1,7 @@
 using Jint.Collections;
 using Jint.Native.Array;
 using Jint.Native.Object;
+using Jint.Native.Symbol;
 using Jint.Runtime;
 using Jint.Runtime.Descriptors;
 using Jint.Runtime.Interop;
@@ -12,10 +13,8 @@ namespace Jint.Native.Function
     /// </summary>
     public sealed class FunctionPrototype : FunctionInstance
     {
-        private static readonly JsString _functionName = new JsString("Function");
-
         private FunctionPrototype(Engine engine)
-            : base(engine, _functionName)
+            : base(engine, JsString.Empty)
         {
         }
 
@@ -33,57 +32,96 @@ namespace Jint.Native.Function
 
         protected override void Initialize()
         {
-            var properties = new PropertyDictionary(5, checkExistingKeys: false)
+            const PropertyFlag propertyFlags = PropertyFlag.Configurable | PropertyFlag.Writable;
+            const PropertyFlag lengthFlags = PropertyFlag.Configurable;
+            var properties = new PropertyDictionary(7, checkExistingKeys: false)
             {
                 ["constructor"] = new PropertyDescriptor(Engine.Function, PropertyFlag.NonEnumerable),
-                ["toString"] = new PropertyDescriptor(new ClrFunctionInstance(Engine, "toString", ToString), true, false, true),
-                ["apply"] = new PropertyDescriptor(new ClrFunctionInstance(Engine, "apply", Apply, 2), true, false, true),
-                ["call"] = new PropertyDescriptor(new ClrFunctionInstance(Engine, "call", CallImpl, 1), true, false, true),
-                ["bind"] = new PropertyDescriptor(new ClrFunctionInstance(Engine, "bind", Bind, 1), true, false, true)
+                ["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),
+                ["arguments"] = _engine._callerCalleeArgumentsThrowerConfigurable,
+                ["caller"] = _engine._callerCalleeArgumentsThrowerConfigurable
             };
             SetProperties(properties);
+            
+            var symbols = new SymbolDictionary(1)
+            {
+                [GlobalSymbolRegistry.HasInstance] = new PropertyDescriptor(new ClrFunctionInstance(_engine, "[Symbol.hasInstance]", HasInstance, 1, PropertyFlag.Configurable), PropertyFlag.AllForbidden)
+            };
+            SetSymbols(symbols);
+        }
+
+        private static JsValue HasInstance(JsValue thisObj, JsValue[] arguments)
+        {
+            if (!(thisObj is FunctionInstance f))
+            {
+                return false;
+            }
+            
+            return f.HasInstance(arguments.At(0));
         }
 
         private JsValue Bind(JsValue thisObj, JsValue[] arguments)
         {
-            var target = thisObj.TryCast<ICallable>(x =>
+            if (!(thisObj is ICallable))
             {
-                ExceptionHelper.ThrowTypeError(Engine);
-            });
+                ExceptionHelper.ThrowTypeError(Engine, "Bind must be called on a function");
+            }
 
             var thisArg = arguments.At(0);
             var f = new BindFunctionInstance(Engine)
             {
                 TargetFunction = thisObj,
-                BoundThis = thisArg,
+                BoundThis = thisObj is ArrowFunctionInstance ? Undefined : thisArg,
                 BoundArgs = arguments.Skip(1),
-                _prototype = Engine.Function.PrototypeObject
+                _prototype = Engine.Function.PrototypeObject,
             };
 
-            if (target is FunctionInstance functionInstance)
+            JsNumber l;
+            var targetHasLength = thisObj.HasOwnProperty(CommonProperties.Length);
+            if (targetHasLength)
             {
-                var l = TypeConverter.ToNumber(functionInstance.Get(CommonProperties.Length, functionInstance)) - (arguments.Length - 1);
-                f.SetOwnProperty(CommonProperties.Length, new PropertyDescriptor(System.Math.Max(l, 0), PropertyFlag.AllForbidden));
+                var targetLen = thisObj.Get(CommonProperties.Length);
+                if (!targetLen.IsNumber())
+                {
+                    l = JsNumber.PositiveZero;
+                }
+                else
+                {
+                    targetLen = TypeConverter.ToInteger(targetLen);
+                    // first argument is target
+                    var argumentsLength = System.Math.Max(0, arguments.Length - 1);
+                    l = JsNumber.Create((uint) System.Math.Max(((JsNumber) targetLen)._value - argumentsLength, 0));
+                }
             }
             else
             {
-                f.SetOwnProperty(CommonProperties.Length, PropertyDescriptor.AllForbiddenDescriptor.NumberZero);
+                l = JsNumber.PositiveZero;
+            }
+
+            f._length = new PropertyDescriptor(l, PropertyFlag.Configurable);
+            
+            var targetName = thisObj.Get(CommonProperties.Name);
+            if (!targetName.IsString())
+            {
+                targetName = JsString.Empty;
             }
 
-            f.DefineOwnProperty(CommonProperties.Caller, _engine._getSetThrower);
-            f.DefineOwnProperty(CommonProperties.Arguments, _engine._getSetThrower);
+            f.SetFunctionName(targetName, "bound");
 
             return f;
         }
 
         private JsValue ToString(JsValue thisObj, JsValue[] arguments)
         {
-            if (!(thisObj is FunctionInstance))
+            if (thisObj.IsObject() && thisObj.IsCallable)
             {
-                return ExceptionHelper.ThrowTypeError<FunctionInstance>(_engine, "Function object expected.");
+                return thisObj.ToString();
             }
 
-            return "function() {{ ... }}";
+            return ExceptionHelper.ThrowTypeError<FunctionInstance>(_engine, "Function.prototype.toString requires that 'this' be a Function");
         }
 
         internal JsValue Apply(JsValue thisObject, JsValue[] arguments)

+ 5 - 5
Jint/Native/Function/ScriptFunctionInstance.cs

@@ -11,7 +11,7 @@ namespace Jint.Native.Function
 {
     public sealed class ScriptFunctionInstance : FunctionInstance, IConstructor
     {
-        internal readonly JintFunctionDefinition _function;
+        private readonly JintFunctionDefinition _function;
 
         /// <summary>
         /// http://www.ecma-international.org/ecma-262/5.1/#sec-13.2
@@ -45,10 +45,10 @@ namespace Jint.Native.Function
 
             _prototypeDescriptor = new PropertyDescriptor(proto, PropertyFlag.OnlyWritable);
 
-            if (thisMode == FunctionThisMode.Strict)
+            if (!function.Strict && !engine._isStrict)
             {
-                DefineOwnProperty(CommonProperties.Caller, engine._getSetThrower);
-                DefineOwnProperty(CommonProperties.Arguments, engine._getSetThrower);
+                DefineOwnProperty(CommonProperties.Arguments, engine._callerCalleeArgumentsThrowerConfigurable);
+                DefineOwnProperty(CommonProperties.Caller, new PropertyDescriptor(Undefined, PropertyFlag.Configurable));
             }
         }
 
@@ -109,7 +109,7 @@ namespace Jint.Native.Function
                         arguments,
                         localEnv);
 
-                    var result = _function.Body.Execute();
+                    var result = _function.Execute();
                     var value = result.GetValueOrDefault().Clone();
                     argumentsInstance?.FunctionWasCalled();
 

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

@@ -7,9 +7,12 @@ namespace Jint.Native.Function
     {
         private static readonly JsString _functionName = new JsString("throwTypeError");
 
-        public ThrowTypeError(Engine engine)
+        private readonly string _message;
+
+        public ThrowTypeError(Engine engine, string message = null)
             : base(engine, _functionName)
         {
+            _message = message;
             _length = PropertyDescriptor.AllForbiddenDescriptor.NumberZero;
             _environment = engine.GlobalEnvironment;
             PreventExtensions();
@@ -17,7 +20,7 @@ namespace Jint.Native.Function
 
         public override JsValue Call(JsValue thisObject, JsValue[] arguments)
         {
-            return ExceptionHelper.ThrowTypeError<JsValue>(_engine);
+            return ExceptionHelper.ThrowTypeError<JsValue>(_engine, _message);
         }
     }
 }

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

@@ -296,12 +296,12 @@ namespace Jint.Native.Iterator
             }
         }
 
-        internal class ObjectWrapper : IIterator
+        internal class ObjectIterator : IIterator
         {
             private readonly ObjectInstance _target;
             private readonly ICallable _nextMethod;
 
-            public ObjectWrapper(ObjectInstance target)
+            public ObjectIterator(ObjectInstance target)
             {
                 _target = target;
                 _nextMethod = target.Get(CommonProperties.Next, target) as ICallable

+ 8 - 2
Jint/Native/JsValue.cs

@@ -128,6 +128,8 @@ namespace Jint.Native
             return _type == InternalTypes.Null;
         }
 
+        internal virtual bool IsIntegerIndexedArray => false;
+
         [Pure]
         [MethodImpl(MethodImplOptions.AggressiveInlining)]
         public bool IsSymbol()
@@ -202,7 +204,7 @@ namespace Jint.Native
             }
             else
             {
-                iterator = new IteratorInstance.ObjectWrapper(obj);
+                iterator = new IteratorInstance.ObjectIterator(obj);
             }
             return true;
         }
@@ -395,7 +397,7 @@ namespace Jint.Native
         /// <returns>The value returned by the function call.</returns>
         internal JsValue Invoke(JsValue thisObj, JsValue[] arguments)
         {
-            var callable = this as ICallable ?? ExceptionHelper.ThrowArgumentException<ICallable>("Can only invoke functions");
+            var callable = this as ICallable ?? ExceptionHelper.ThrowTypeErrorNoEngine<ICallable>("Can only invoke functions");
             return callable.Call(thisObj, arguments);
         }
         
@@ -413,6 +415,8 @@ namespace Jint.Native
             return callable.Call(v, arguments);
         }
 
+        public virtual bool HasOwnProperty(JsValue property) => false;
+        
         [MethodImpl(MethodImplOptions.AggressiveInlining)]
         public JsValue Get(JsValue property)
         {
@@ -594,6 +598,8 @@ namespace Jint.Native
         {
             return this;
         }
+        
+        internal virtual bool IsCallable => this is ICallable;
 
         internal static bool SameValue(JsValue x, JsValue y)
         {

+ 11 - 3
Jint/Native/Object/ObjectConstructor.cs

@@ -285,7 +285,11 @@ namespace Jint.Native.Object
 
         private JsValue DefineProperty(JsValue thisObject, JsValue[] arguments)
         {
-            var o = arguments.As<ObjectInstance>(0, _engine);
+            if (!(arguments.At(0) is ObjectInstance o))
+            {
+                return ExceptionHelper.ThrowTypeError<JsValue>(_engine, "Object.defineProperty called on non-object");
+            }
+
             var p = arguments.At(1);
             var name = TypeConverter.ToPropertyKey(p);
 
@@ -293,12 +297,16 @@ namespace Jint.Native.Object
             var desc = PropertyDescriptor.ToPropertyDescriptor(Engine, attributes);
             o.DefinePropertyOrThrow(name, desc);
 
-            return o;
+            return arguments.At(0);
         }
 
         private JsValue DefineProperties(JsValue thisObject, JsValue[] arguments)
         {
-            var o = arguments.As<ObjectInstance>(0, _engine);
+            if (!(arguments.At(0) is ObjectInstance o))
+            {
+                return ExceptionHelper.ThrowTypeError<JsValue>(_engine, "Object.defineProperty called on non-object");
+            }
+
             var properties = arguments.At(1);
             var props = TypeConverter.ToObject(Engine, properties);
             var descriptors = new List<KeyValuePair<JsValue, PropertyDescriptor>>();

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

@@ -276,7 +276,7 @@ namespace Jint.Native.Object
             return _symbols?.TryGetValue((JsSymbol) key, out descriptor) == true;
         }
 
-        public virtual bool HasOwnProperty(JsValue property)
+        public override bool HasOwnProperty(JsValue property)
         {
             EnsureInitialized();
 
@@ -1095,6 +1095,7 @@ namespace Jint.Native.Object
                                            && lengthValue.IsNumber()
                                            && ((JsNumber) lengthValue)._value >= 0;
 
+        internal override bool IsIntegerIndexedArray => false;
 
         public virtual uint Length => (uint) TypeConverter.ToLength(Get(CommonProperties.Length));
 

+ 10 - 6
Jint/Native/Proxy/ProxyInstance.cs

@@ -1,12 +1,12 @@
 using System.Collections.Generic;
-using Jint.Native.Function;
+
 using Jint.Native.Object;
 using Jint.Runtime;
 using Jint.Runtime.Descriptors;
 
 namespace Jint.Native.Proxy
 {
-    public class ProxyInstance : FunctionInstance, IConstructor
+    public class ProxyInstance : ObjectInstance, IConstructor, ICallable
     {
         internal ObjectInstance _target;
         internal ObjectInstance _handler;
@@ -32,13 +32,13 @@ namespace Jint.Native.Proxy
             Engine engine,
             ObjectInstance target,
             ObjectInstance handler)
-            : base(engine, JsString.Empty, FunctionThisMode.Global, target.Class)
+            : base(engine, target.Class)
         {
             _target = target;
             _handler = handler;
         }
 
-        public override JsValue Call(JsValue thisObject, JsValue[] arguments)
+        public JsValue Call(JsValue thisObject, JsValue[] arguments)
         {
             var jsValues = new[] { _target, thisObject, _engine.Array.Construct(arguments) };
             if (TryCallHandler(TrapApply, jsValues, out var result))
@@ -181,7 +181,7 @@ namespace Jint.Native.Proxy
 
         public override PropertyDescriptor GetOwnProperty(JsValue property)
         {
-            if (!TryCallHandler(TrapGetOwnPropertyDescriptor, new[] {_target, property, this}, out var result))
+            if (!TryCallHandler(TrapGetOwnPropertyDescriptor, new[] { _target, property }, out var result))
             {
                 return _target.GetOwnProperty(property);
             }
@@ -444,6 +444,8 @@ namespace Jint.Native.Proxy
             return true;
         }
 
+        internal override bool IsCallable => _target is ICallable;
+
         private bool TryCallHandler(JsValue propertyName, JsValue[] arguments, out JsValue result)
         {
             AssertNotRevoked(propertyName);
@@ -464,7 +466,7 @@ namespace Jint.Native.Proxy
             return false;
         }
 
-        internal void AssertNotRevoked(JsValue key)
+        private void AssertNotRevoked(JsValue key)
         {
             if (_handler is null)
             {
@@ -479,5 +481,7 @@ namespace Jint.Native.Proxy
                 ExceptionHelper.ThrowTypeError(_engine, $"Cannot perform '{key}' on a proxy that has been revoked");
             }
         }
+        
+        public override string ToString() => "function () { [native code] }";
     }
 }

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

@@ -76,7 +76,11 @@ namespace Jint.Native.Reflect
 
         private JsValue DefineProperty(JsValue thisObject, JsValue[] arguments)
         {
-            var o = arguments.As<ObjectInstance>(0, _engine);
+            if (!(arguments.At(0) is ObjectInstance o))
+            {
+                return ExceptionHelper.ThrowTypeError<JsValue>(_engine, "Reflect.defineProperty called on non-object");
+            }
+
             var p = arguments.At(1);
             var name = TypeConverter.ToPropertyKey(p);
 

+ 92 - 13
Jint/Options.cs

@@ -6,36 +6,30 @@ using System.Reflection;
 using Jint.Native;
 using Jint.Native.Object;
 using Jint.Runtime.Interop;
+using Jint.Runtime.References;
 
 namespace Jint
 {
+    public delegate JsValue MemberAccessorDelegate(Engine engine, object target, string member);
+
     public sealed class Options
     {
         private readonly List<IConstraint> _constraints = new List<IConstraint>();
-        private bool _discardGlobal;
         private bool _strict;
         private bool _allowDebuggerStatement;
         private bool _allowClr;
         private bool _allowClrWrite = true;
         private readonly List<IObjectConverter> _objectConverters = new List<IObjectConverter>();
         private Func<Engine, object, ObjectInstance> _wrapObjectHandler;
+        private MemberAccessorDelegate _memberAccessor;
         private int _maxRecursionDepth = -1;
         private TimeSpan _regexTimeoutInterval = TimeSpan.FromSeconds(10);
         private CultureInfo _culture = CultureInfo.CurrentCulture;
         private TimeZoneInfo _localTimeZone = TimeZoneInfo.Local;
         private List<Assembly> _lookupAssemblies = new List<Assembly>();
         private Predicate<Exception> _clrExceptionsHandler;
-        private IReferenceResolver _referenceResolver;
-
-        /// <summary>
-        /// When called, doesn't initialize the global scope.
-        /// Can be useful in lightweight scripts for performance reason.
-        /// </summary>
-        public Options DiscardGlobal(bool discard = true)
-        {
-            _discardGlobal = discard;
-            return this;
-        }
+        private IReferenceResolver _referenceResolver = DefaultReferenceResolver.Instance;
+        private readonly List<Action<Engine>> _configurations = new List<Action<Engine>>();
 
         /// <summary>
         /// Run the script in strict mode.
@@ -68,6 +62,14 @@ namespace Jint
             return this;
         }
 
+        /// <summary>
+        /// Adds a <see cref="IObjectConverter"/> instance to convert CLR types to <see cref="JsValue"/>
+        /// </summary>
+        public Options AddObjectConverter<T>() where T : IObjectConverter, new()
+        {
+            return AddObjectConverter(new T());
+        }
+
         /// <summary>
          /// Adds a <see cref="IObjectConverter"/> instance to convert CLR types to <see cref="JsValue"/>
         /// </summary>
@@ -88,6 +90,30 @@ namespace Jint
             return this;
         }
 
+        /// <summary>
+        /// Sets the type converter to use.
+        /// </summary>
+        public Options SetTypeConverter(Func<Engine, ITypeConverter> typeConverterFactory)
+        {
+            _configurations.Add(engine => engine.ClrTypeConverter = typeConverterFactory(engine));
+            return this;
+        }
+
+        /// <summary>
+        /// Registers a delegate that is called when CLR members are invoked. This allows
+        /// to change what values are returned for specific CLR objects, or if any value 
+        /// is returned at all.
+        /// </summary>
+        /// <param name="accessor">
+        /// The delegate to invoke for each CLR member. If the delegate 
+        /// returns <c>null</c>, the standard evaluation is performed.
+        /// </param>
+        public Options SetMemberAccessor(MemberAccessorDelegate accessor)
+        {
+            _memberAccessor = accessor;
+            return this;
+        }
+
         /// <summary>
         /// Allows scripts to call CLR types directly like <example>System.IO.File</example>
         /// </summary>
@@ -181,7 +207,28 @@ namespace Jint
             return this;
         }
 
-        internal bool _IsGlobalDiscarded => _discardGlobal;
+        /// <summary>
+        /// Registers some custom logic to apply on an <see cref="Engine"/> instance when the options
+        /// are loaded.
+        /// </summary>
+        /// <param name="configuration">The action to register.</param>
+        public Options Configure(Action<Engine> configuration)
+        {
+            _configurations.Add(configuration);
+            return this;
+        }
+
+        /// <summary>
+        /// Called by the <see cref="Engine"/> instance that loads this <see cref="Options" />
+        /// once it is loaded.
+        /// </summary>
+        internal void Apply(Engine engine)
+        {
+            foreach (var configuration in _configurations)
+            {
+                configuration?.Invoke(engine);
+            }
+        }
 
         internal bool IsStrict => _strict;
 
@@ -202,6 +249,7 @@ namespace Jint
         internal List<IConstraint> _Constraints => _constraints;
 
         internal Func<Engine, object, ObjectInstance> _WrapObjectHandler => _wrapObjectHandler;
+        internal MemberAccessorDelegate _MemberAccessor => _memberAccessor;
 
         internal int MaxRecursionDepth => _maxRecursionDepth;
 
@@ -212,5 +260,36 @@ namespace Jint
         internal TimeZoneInfo _LocalTimeZone => _localTimeZone;
 
         internal IReferenceResolver  ReferenceResolver => _referenceResolver;
+        
+        private sealed class DefaultReferenceResolver : IReferenceResolver
+        {
+            public static readonly DefaultReferenceResolver Instance = new DefaultReferenceResolver();
+            
+            private DefaultReferenceResolver()
+            {
+            }
+
+            public bool TryUnresolvableReference(Engine engine, Reference reference, out JsValue value)
+            {
+                value = JsValue.Undefined;
+                return false;
+            }
+
+            public bool TryPropertyReference(Engine engine, Reference reference, ref JsValue value)
+            {
+                return false;
+            }
+
+            public bool TryGetCallable(Engine engine, object callee, out JsValue value)
+            {
+                value = JsValue.Undefined;
+                return false;
+            }
+
+            public bool CheckCoercible(JsValue value)
+            {
+                return false;
+            }
+        }
     }
 }

+ 0 - 12
Jint/Runtime/Arguments.cs

@@ -32,18 +32,6 @@ namespace Jint.Runtime
             return At(args, index, Undefined.Instance);
         }
 
-        [MethodImpl(MethodImplOptions.AggressiveInlining)]
-        public static T As<T>(this JsValue[] args, int index, Engine engine) where T : JsValue
-        {
-            var value = (uint) index < (uint) args.Length ? args[index] as T : null;
-            if (value is null)
-            {
-                ExceptionHelper.ThrowTypeError<JsValue>(engine);
-            }
-
-            return value;
-        }
-
         [MethodImpl(MethodImplOptions.AggressiveInlining)]
         public static JsValue[] Skip(this JsValue[] args, int count)
         {

+ 1 - 1
Jint/Runtime/Descriptors/Specialized/FieldInfoDescriptor.cs

@@ -4,7 +4,7 @@ using Jint.Native;
 
 namespace Jint.Runtime.Descriptors.Specialized
 {
-    public sealed class FieldInfoDescriptor : PropertyDescriptor
+    internal sealed class FieldInfoDescriptor : PropertyDescriptor
     {
         private readonly Engine _engine;
         private readonly FieldInfo _fieldInfo;

+ 12 - 10
Jint/Runtime/Descriptors/Specialized/GetSetPropertyDescriptor.cs

@@ -1,8 +1,9 @@
 using Jint.Native;
+using Jint.Native.Function;
 
 namespace Jint.Runtime.Descriptors.Specialized
 {
-    public sealed class GetSetPropertyDescriptor : PropertyDescriptor
+    internal sealed class GetSetPropertyDescriptor : PropertyDescriptor
     {
         private JsValue _get;
         private JsValue _set;
@@ -42,18 +43,19 @@ namespace Jint.Runtime.Descriptors.Specialized
 
         internal sealed class ThrowerPropertyDescriptor : PropertyDescriptor
         {
-            private readonly JsValue _get;
-            private readonly JsValue _set;
-
-            public ThrowerPropertyDescriptor(JsValue functionThrowTypeError)
-                : base(PropertyFlag.EnumerableSet | PropertyFlag.ConfigurableSet | PropertyFlag.CustomJsValue)
+            private readonly Engine _engine;
+            private readonly string _message;
+            private JsValue _thrower;
+            
+            public ThrowerPropertyDescriptor(Engine engine, PropertyFlag flags, string message)
+                : base(flags)
             {
-                _get = functionThrowTypeError;
-                _set = functionThrowTypeError;
+                _engine = engine;
+                _message = message;
             }
 
-            public override JsValue Get => _get;
-            public override JsValue Set => _set;
+            public override JsValue Get => _thrower ??= new ThrowTypeError(_engine, _message) { _prototype = _engine.Function.PrototypeObject};
+            public override JsValue Set => _thrower ??= new ThrowTypeError(_engine, _message) { _prototype = _engine.Function.PrototypeObject};
 
             protected internal override JsValue CustomValue
             {

+ 54 - 28
Jint/Runtime/Descriptors/Specialized/IndexDescriptor.cs

@@ -1,11 +1,13 @@
 using System;
+using System.Collections;
+using System.Collections.Generic;
 using System.Globalization;
 using System.Reflection;
 using Jint.Native;
 
 namespace Jint.Runtime.Descriptors.Specialized
 {
-    public sealed class IndexDescriptor : PropertyDescriptor
+    internal sealed class IndexDescriptor : PropertyDescriptor
     {
         private readonly Engine _engine;
         private readonly object _key;
@@ -13,34 +15,56 @@ namespace Jint.Runtime.Descriptors.Specialized
         private readonly PropertyInfo _indexer;
         private readonly MethodInfo _containsKey;
 
-        public IndexDescriptor(Engine engine, Type targetType, string key, object target) : base(PropertyFlag.CustomJsValue)
+        private static readonly PropertyInfo _iListIndexer = typeof(IList).GetProperty("Item");
+
+        internal IndexDescriptor(Engine engine, object target, PropertyInfo indexer, MethodInfo containsKey, object key)
+            : base(PropertyFlag.Enumerable | PropertyFlag.CustomJsValue)
         {
             _engine = engine;
             _target = target;
-
-            if (!TryFindIndexer(engine, targetType, key, out _indexer, out _containsKey, out _key))
-            {
-                ExceptionHelper.ThrowArgumentException("invalid indexing configuration, target indexer not found");
-            }
-
+            _indexer = indexer;
+            _containsKey = containsKey;
+            _key = key;
             Writable = engine.Options._IsClrWriteAllowed;
         }
 
-        public IndexDescriptor(Engine engine, string key, object item)
-            : this(engine, item.GetType(), key, item)
-        {
-        }
-
         internal static bool TryFindIndexer(
             Engine engine,
             Type targetType,
             string propertyName,
-            out PropertyInfo indexerProperty,
-            out MethodInfo containsKeyMethod,
-            out object indexerKey)
+            out Func<object, IndexDescriptor> factory)
         {
-            // get all instance indexers with exactly 1 argument
             var paramTypeArray = new Type[1];
+            Func<object, IndexDescriptor> ComposeIndexerFactory(PropertyInfo candidate, Type paramType)
+            {
+                if (engine.ClrTypeConverter.TryConvert(propertyName, paramType, CultureInfo.InvariantCulture, out var key))
+                {
+                    // the key can be converted for this indexer
+                    var indexerProperty = candidate;
+                    // get contains key method to avoid index exception being thrown in dictionaries
+                    paramTypeArray[0] = paramType;
+                    var containsKeyMethod = targetType.GetMethod(nameof(IDictionary<string,string>.ContainsKey), paramTypeArray);
+                    if (containsKeyMethod is null)
+                    {
+                        paramTypeArray[0] = typeof(object);
+                        containsKeyMethod = targetType.GetMethod(nameof(IDictionary.Contains), paramTypeArray);
+                    }
+                    return (target) => new IndexDescriptor(engine, target, indexerProperty, containsKeyMethod, key);
+                }
+
+                // the key type doesn't work for this indexer
+                return null;
+            }
+
+            // default indexer wins
+            if (typeof(IList).IsAssignableFrom(targetType))
+            {
+                factory = ComposeIndexerFactory(_iListIndexer, typeof(int));
+                if (factory != null)
+                {
+                    return true;
+                }
+            }
 
             // try to find first indexer having either public getter or setter with matching argument type
             foreach (var candidate in targetType.GetProperties())
@@ -54,21 +78,15 @@ namespace Jint.Runtime.Descriptors.Specialized
                 if (candidate.GetGetMethod() != null || candidate.GetSetMethod() != null)
                 {
                     var paramType = indexParameters[0].ParameterType;
-
-                    if (engine.ClrTypeConverter.TryConvert(propertyName, paramType, CultureInfo.InvariantCulture, out indexerKey))
+                    factory = ComposeIndexerFactory(candidate, paramType);
+                    if (factory != null)
                     {
-                        indexerProperty = candidate;
-                        // get contains key method to avoid index exception being thrown in dictionaries
-                        paramTypeArray[0] = paramType;
-                        containsKeyMethod = targetType.GetMethod("ContainsKey", paramTypeArray);
                         return true;
                     }
                 }
             }
 
-            indexerProperty = default;
-            containsKeyMethod = default;
-            indexerKey = default;
+            factory = default;
             return false;
         }
 
@@ -104,8 +122,8 @@ namespace Jint.Runtime.Descriptors.Specialized
                         case null:
                             throw;
                         case ArgumentOutOfRangeException _:
-                            return JsValue.Undefined;
                         case IndexOutOfRangeException _:
+                        case InvalidOperationException _:
                             return JsValue.Undefined;
                         default:
                             throw tie.InnerException;
@@ -120,7 +138,15 @@ namespace Jint.Runtime.Descriptors.Specialized
                     ExceptionHelper.ThrowInvalidOperationException("Indexer has no public setter.");
                 }
 
-                object[] parameters = { _key,  value?.ToObject() };
+                var obj = value?.ToObject();
+                
+                // attempt to convert to expected type
+                if (obj != null && obj.GetType() != _indexer.PropertyType)
+                {
+                    obj = _engine.ClrTypeConverter.Convert(obj, _indexer.PropertyType, CultureInfo.InvariantCulture);
+                }
+                
+                object[] parameters = { _key,  obj };
                 try
                 {
                     setter!.Invoke(_target, parameters);

+ 3 - 2
Jint/Runtime/Descriptors/Specialized/PropertyInfoDescriptor.cs

@@ -4,13 +4,14 @@ using Jint.Native;
 
 namespace Jint.Runtime.Descriptors.Specialized
 {
-    public sealed class PropertyInfoDescriptor : PropertyDescriptor
+    internal sealed class PropertyInfoDescriptor : PropertyDescriptor
     {
         private readonly Engine _engine;
         private readonly PropertyInfo _propertyInfo;
         private readonly object _item;
 
-        public PropertyInfoDescriptor(Engine engine, PropertyInfo propertyInfo, object item) : base(PropertyFlag.CustomJsValue)
+        public PropertyInfoDescriptor(Engine engine, PropertyInfo propertyInfo, object item) 
+            : base(PropertyFlag.Enumerable | PropertyFlag.CustomJsValue)
         {
             _engine = engine;
             _propertyInfo = propertyInfo;

+ 5 - 0
Jint/Runtime/ExceptionHelper.cs

@@ -182,5 +182,10 @@ namespace Jint.Runtime
         {
             throw new MemoryLimitExceededException(message);
         }
+
+        public static void ThrowExecutionCanceledException()
+        {
+            throw new ExecutionCanceledException();
+        }
     }
 }

+ 9 - 0
Jint/Runtime/ExecutionCanceledException.cs

@@ -0,0 +1,9 @@
+namespace Jint.Runtime
+{
+    public class ExecutionCanceledException : JintException
+    {
+        public ExecutionCanceledException() : base("The script execution was canceled.")
+        {
+        }
+    }
+}

+ 7 - 0
Jint/Runtime/Interop/ClrFunctionInstance.cs

@@ -10,6 +10,7 @@ namespace Jint.Runtime.Interop
     /// </summary>
     public sealed class ClrFunctionInstance : FunctionInstance, IEquatable<ClrFunctionInstance>
     {
+        private readonly string _name;
         internal readonly Func<JsValue, JsValue[], JsValue> _func;
 
         public ClrFunctionInstance(
@@ -20,6 +21,7 @@ namespace Jint.Runtime.Interop
             PropertyFlag lengthFlags = PropertyFlag.AllForbidden)
             : base(engine, !string.IsNullOrWhiteSpace(name) ? new JsString(name) : null)
         {
+            _name = name;
             _func = func;
 
             _prototype = engine.Function.PrototypeObject;
@@ -65,5 +67,10 @@ namespace Jint.Runtime.Interop
             
             return false;
         }
+
+        public override string ToString()
+        {
+            return $"function {_name}() {{ [native code] }}";
+        }
     }
 }

+ 38 - 0
Jint/Runtime/Interop/ClrPropertyDescriptorFactoriesKey.cs

@@ -0,0 +1,38 @@
+using System;
+
+namespace Jint.Runtime.Interop
+{
+    internal readonly struct ClrPropertyDescriptorFactoriesKey : IEquatable<ClrPropertyDescriptorFactoriesKey>
+    {
+        public ClrPropertyDescriptorFactoriesKey(Type type, Key propertyName)
+        {
+            Type = type;
+            PropertyName = propertyName;
+        }
+
+        private readonly Type Type;
+        private readonly Key PropertyName;
+
+        public bool Equals(ClrPropertyDescriptorFactoriesKey other)
+        {
+            return Type == other.Type && PropertyName == other.PropertyName;
+        }
+
+        public override bool Equals(object obj)
+        {
+            if (ReferenceEquals(null, obj))
+            {
+                return false;
+            }
+            return obj is ClrPropertyDescriptorFactoriesKey other && Equals(other);
+        }
+
+        public override int GetHashCode()
+        {
+            unchecked
+            {
+                return (Type.GetHashCode() * 397) ^ PropertyName.GetHashCode();
+            }
+        }
+    }
+}

+ 42 - 0
Jint/Runtime/Interop/IReferenceResolver.cs

@@ -3,11 +3,53 @@ using Jint.Runtime.References;
 
 namespace Jint.Runtime.Interop
 {
+    /// <summary>
+    /// Reference resolver allows customizing behavior for reference resolving. This can be useful in cases where
+    /// you want to ignore long chain of property accesses that might throw if anything is null or undefined.
+    /// An example of such is <code>var a = obj.field.subField.value</code>. Custom resolver could accept chain to return
+    /// null/undefined on first occurrence. 
+    /// </summary>
     public interface IReferenceResolver
     {
+        /// <summary>
+        /// When unresolvable reference occurs, check if another value can be provided instead of it. 
+        /// </summary>
+        /// <remarks>
+        /// A reference error will be thrown if this method return false.
+        /// </remarks>
+        /// <param name="engine">The current engine instance.</param>
+        /// <param name="reference">The reference that is being processed.</param>
+        /// <param name="value">Value that should be used instead of undefined.</param>
+        /// <returns>Whether to use <paramref name="value" /> instead of undefined.</returns>
         bool TryUnresolvableReference(Engine engine, Reference reference, out JsValue value);
+
+        /// <summary>
+        /// When property reference is being processed, resolve to other value if needed.  
+        /// </summary>
+        /// <param name="engine">The current engine instance.</param>
+        /// <param name="reference">The reference that is being processed.</param>
+        /// <param name="value">Value that should be used instead of reference target.</param>
+        /// <returns>Whether to use <paramref name="value" /> instead of reference's value.</returns>
         bool TryPropertyReference(Engine engine, Reference reference, ref JsValue value);
+        
+        /// <summary>
+        /// When evaluating a function call and a target that is not an object is encountered,
+        /// custom implementation can return a value to call. 
+        /// </summary>
+        /// <remarks>
+        /// A reference error will be thrown if this method return false.
+        /// </remarks>
+        /// <param name="engine">The current engine instance.</param>
+        /// <param name="callee">The callee.</param>
+        /// <param name="value">Value that should be used when this method return true. Should be <see cref="ICallable"/>.</param>
+        /// <returns>Whether to use <paramref name="value" /> instead of undefined.</returns>
         bool TryGetCallable(Engine engine, object callee, out JsValue value);
+        
+        /// <summary>
+        /// Check whether objects property value is valid.
+        /// </summary>
+        /// <param name="value">The value to check</param>
+        /// <returns>Whether to accept the value.</returns>
         bool CheckCoercible(JsValue value);
     }
 }

+ 125 - 13
Jint/Runtime/Interop/ObjectWrapper.cs

@@ -1,9 +1,11 @@
 using System;
 using System.Collections;
 using System.Collections.Generic;
+using System.Globalization;
 using System.Reflection;
 using Jint.Native;
 using Jint.Native.Object;
+using Jint.Native.Symbol;
 using Jint.Runtime.Descriptors;
 using Jint.Runtime.Descriptors.Specialized;
 
@@ -28,9 +30,11 @@ namespace Jint.Runtime.Interop
                     return;
                 }
                 IsArrayLike = true;
+                IsIntegerIndexedArray = typeof(IList).IsAssignableFrom(type);
+
                 var functionInstance = new ClrFunctionInstance(engine, "length", (thisObj, arguments) => JsNumber.Create((int) lengthProperty.GetValue(obj)));
                 var descriptor = new GetSetPropertyDescriptor(functionInstance, Undefined, PropertyFlag.Configurable);
-                AddProperty(CommonProperties.Length, descriptor);
+                SetProperty(KnownKeys.Length, descriptor);
             }
         }
 
@@ -62,6 +66,8 @@ namespace Jint.Runtime.Interop
 
         public override bool IsArrayLike { get; }
 
+        internal override bool IsIntegerIndexedArray { get; }
+
         public override bool Set(JsValue property, JsValue value, JsValue receiver)
         {
             if (!CanPut(property))
@@ -80,20 +86,122 @@ namespace Jint.Runtime.Interop
             return true;
         }
 
-        public override PropertyDescriptor GetOwnProperty(JsValue property)
+        public override JsValue Get(JsValue property, JsValue receiver)
         {
             if (property.IsSymbol())
             {
-                return PropertyDescriptor.Undefined;
+                // wrapped objects cannot have symbol properties
+                return Undefined;
+            }
+
+            if (property.IsInteger() && Target is IList list)
+            {
+                var index = (int) ((JsNumber) property)._value;
+                return (uint) index < list.Count ? FromObject(_engine, list[index]) : Undefined;
             }
 
+            return base.Get(property, receiver);
+        }
+
+        public override List<JsValue> GetOwnPropertyKeys(Types types = Types.None | Types.String | Types.Symbol)
+        {
+            return new List<JsValue>(EnumerateOwnPropertyKeys(types));
+        }
+
+        public override IEnumerable<KeyValuePair<JsValue, PropertyDescriptor>> GetOwnProperties()
+        {
+            foreach (var key in EnumerateOwnPropertyKeys(Types.String | Types.Symbol))
+            {
+                yield return new KeyValuePair<JsValue, PropertyDescriptor>(key, GetOwnProperty(key));
+            }
+        }
+
+        private IEnumerable<JsValue> EnumerateOwnPropertyKeys(Types types)
+        {
+            var basePropertyKeys = base.GetOwnPropertyKeys(types);
+            // prefer object order, add possible other properties after
+            var processed = basePropertyKeys.Count > 0 ? new HashSet<JsValue>() : null;
+
+            var includeStrings = (types & Types.String) != 0;
+            if (Target is IDictionary dictionary && includeStrings)
+            {
+                // we take values exposed as dictionary keys only 
+                foreach (var key in dictionary.Keys)
+                {
+                    if (_engine.ClrTypeConverter.TryConvert(key, typeof(string), CultureInfo.InvariantCulture, out var stringKey))
+                    {
+                        var jsString = JsString.Create((string) stringKey);
+                        processed?.Add(jsString);
+                        yield return jsString;
+                    }
+                }
+            }
+            else if (includeStrings)
+            {
+                // we take public properties and fields
+                var type = Target.GetType();
+                foreach (var p in type.GetProperties(BindingFlags.Static | BindingFlags.Instance | BindingFlags.Public))
+                {
+                    var indexParameters = p.GetIndexParameters();
+                    if (indexParameters.Length == 0)
+                    {
+                        var jsString = JsString.Create(p.Name);
+                        processed?.Add(jsString);
+                        yield return jsString;
+                    }
+                }
+
+                foreach (var f in type.GetFields(BindingFlags.Static | BindingFlags.Instance | BindingFlags.Public))
+                {
+                    var jsString = JsString.Create(f.Name);
+                    processed?.Add(jsString);
+                    yield return jsString;
+                }
+            }
+
+            if (processed != null)
+            {
+                // we have base keys
+                for (var i = 0; i < basePropertyKeys.Count; i++)
+                {
+                    var key = basePropertyKeys[i];
+                    if (processed.Add(key))
+                    {
+                        yield return key;
+                    }
+                }
+            }
+        }
+
+        public override PropertyDescriptor GetOwnProperty(JsValue property)
+        {
             if (TryGetProperty(property, out var x))
             {
                 return x;
             }
 
+            if (property.IsSymbol() && property == GlobalSymbolRegistry.Iterator)
+            {
+                var iteratorFunction = new ClrFunctionInstance(Engine, "iterator", (thisObject, arguments) => _engine.Iterator.Construct(this), 1, PropertyFlag.Configurable);
+                var iteratorProperty = new PropertyDescriptor(iteratorFunction, PropertyFlag.Configurable | PropertyFlag.Writable);
+                SetProperty(GlobalSymbolRegistry.Iterator, iteratorProperty);
+                return iteratorProperty;
+            }
+
+            var memberAccessor = Engine.Options._MemberAccessor;
+
+            if (memberAccessor != null)
+            {
+                var result = memberAccessor.Invoke(Engine, Target, property.ToString());
+
+                if (result != null)
+                {
+                    return new PropertyDescriptor(result, PropertyFlag.OnlyEnumerable);
+                }
+            }
+
             var type = Target.GetType();
-            var key = new Engine.ClrPropertyDescriptorFactoriesKey(type, property.ToString());
+            var key = new ClrPropertyDescriptorFactoriesKey(type, property.ToString());
 
             if (!_engine.ClrPropertyDescriptorFactories.TryGetValue(key, out var factory))
             {
@@ -113,11 +221,13 @@ namespace Jint.Runtime.Interop
             // properties and fields cannot be numbers
             if (!isNumber)
             {
-                // look for a property
+                // look for a property, bit be wary of indexers, we don't want indexers which have name "Item" to take precedence
                 PropertyInfo property = null;
                 foreach (var p in type.GetProperties(BindingFlags.Static | BindingFlags.Instance | BindingFlags.Public))
                 {
-                    if (EqualsIgnoreCasing(p.Name, propertyName))
+                    // only if it's not an indexer, we can do case-ignoring matches
+                    var isStandardIndexer = p.GetIndexParameters().Length == 1 && p.Name == "Item";
+                    if (!isStandardIndexer && EqualsIgnoreCasing(p.Name, propertyName))
                     {
                         property = p;
                         break;
@@ -158,15 +268,16 @@ namespace Jint.Runtime.Interop
 
                 if (methods?.Count > 0)
                 {
-                    return (engine, target) => new PropertyDescriptor(new MethodInfoFunctionInstance(engine, methods.ToArray()), PropertyFlag.OnlyEnumerable);
+                    var array = methods.ToArray();
+                    return (engine, target) => new PropertyDescriptor(new MethodInfoFunctionInstance(engine, array), PropertyFlag.OnlyEnumerable);
                 }
 
             }
 
             // if no methods are found check if target implemented indexing
-            if (IndexDescriptor.TryFindIndexer(_engine, type, propertyName, out _, out _, out _))
+            if (IndexDescriptor.TryFindIndexer(_engine, type, propertyName, out var indexerFactory))
             {
-                return (engine, target) => new IndexDescriptor(engine, propertyName, target);
+                return (engine, target) => indexerFactory(target);
             }
 
             // try to find a single explicit property implementation
@@ -204,15 +315,16 @@ namespace Jint.Runtime.Interop
 
             if (explicitMethods?.Count > 0)
             {
-                return (engine, target) => new PropertyDescriptor(new MethodInfoFunctionInstance(engine, explicitMethods.ToArray()), PropertyFlag.OnlyEnumerable);
+                var array = explicitMethods.ToArray();
+                return (engine, target) => new PropertyDescriptor(new MethodInfoFunctionInstance(engine, array), PropertyFlag.OnlyEnumerable);
             }
 
             // try to find explicit indexer implementations
-            foreach (Type interfaceType in type.GetInterfaces())
+            foreach (var interfaceType in type.GetInterfaces())
             {
-                if (IndexDescriptor.TryFindIndexer(_engine, interfaceType, propertyName, out _, out _, out _))
+                if (IndexDescriptor.TryFindIndexer(_engine, interfaceType, propertyName, out var interfaceIndexerFactory))
                 {
-                    return (engine, target) => new IndexDescriptor(engine, interfaceType, propertyName, target);
+                    return (engine, target) => interfaceIndexerFactory(target);
                 }
             }
 

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

@@ -129,10 +129,9 @@ namespace Jint.Runtime.Interpreter.Expressions
 
             if (!func.IsObject())
             {
-                if (_engine._referenceResolver == null || !_engine._referenceResolver.TryGetCallable(_engine, callee, out func))
+                if (!_engine._referenceResolver.TryGetCallable(_engine, callee, out func))
                 {
-                    ExceptionHelper.ThrowTypeError(_engine,
-                        r == null ? "" : $"Property '{r.GetReferencedName()}' of object is not a function");
+                    ExceptionHelper.ThrowTypeError(_engine, r == null ? "" : $"Property '{r.GetReferencedName()}' of object is not a function");
                 }
             }
 

+ 8 - 2
Jint/Runtime/Interpreter/Expressions/JintMemberExpression.cs

@@ -84,8 +84,14 @@ namespace Jint.Runtime.Interpreter.Expressions
             }
 
             var property = _determinedProperty ?? _propertyExpression.GetValue();
-            TypeConverter.CheckObjectCoercible(_engine, baseValue, (MemberExpression) _expression, baseReferenceName);
-            return _engine._referencePool.Rent(baseValue,  TypeConverter.ToPropertyKey(property), isStrictModeCode);
+            TypeConverter.CheckObjectCoercible(_engine, baseValue, (MemberExpression) _expression, _determinedProperty?.ToString() ?? baseReferenceName);
+
+            // only convert if necessary
+            var propertyKey = property.IsInteger() && baseValue.IsIntegerIndexedArray
+                ? property
+                : TypeConverter.ToPropertyKey(property);
+
+            return _engine._referencePool.Rent(baseValue, propertyKey, isStrictModeCode);
         }
     }
 }

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

@@ -9,7 +9,7 @@ using Jint.Runtime.Descriptors.Specialized;
 namespace Jint.Runtime.Interpreter.Expressions
 {
     /// <summary>
-    /// http://www.ecma-international.org/ecma-262/5.1/#sec-11.1.5
+    /// http://www.ecma-international.org/ecma-262/#sec-object-initializer
     /// </summary>
     internal sealed class JintObjectExpression : JintExpression
     {

+ 1 - 7
Jint/Runtime/Interpreter/Expressions/JintUnaryExpression.cs

@@ -1,6 +1,5 @@
 using Esprima.Ast;
 using Jint.Native;
-using Jint.Native.Proxy;
 using Jint.Runtime.Environments;
 using Jint.Runtime.References;
 
@@ -138,12 +137,7 @@ namespace Jint.Runtime.Interpreter.Expressions
                         case Types.Symbol: return JsString.SymbolString;
                     }
 
-                    if (v is ProxyInstance)
-                    {
-                        return JsString.ObjectString;
-                    }
-
-                    if (v is ICallable)
+                    if (v.IsCallable)
                     {
                         return JsString.FunctionString;
                     }

+ 13 - 15
Jint/Runtime/Interpreter/JintFunctionDefinition.cs

@@ -3,7 +3,7 @@ using System.Collections.Generic;
 using Esprima.Ast;
 using Jint.Native;
 using Jint.Native.Function;
-using Jint.Runtime.Interpreter.Statements;
+using Jint.Runtime.Interpreter.Expressions;
 
 namespace Jint.Runtime.Interpreter
 {
@@ -14,8 +14,9 @@ namespace Jint.Runtime.Interpreter
     {
         private readonly Engine _engine;
         
-        private JintStatement _body;
-        
+        private JintExpression _bodyExpression;
+        private JintStatementList _bodyStatementList;
+
         public readonly string Name;
         public readonly bool Strict;
         public readonly IFunction Function;
@@ -47,21 +48,18 @@ namespace Jint.Runtime.Interpreter
             }
         }
 
-        public JintStatement Body
+        internal Completion Execute()
         {
-            get
+            if (Function.Expression)
             {
-                if (_body != null)
-                {
-                    return _body;
-                }
-
-                _body = Function.Expression
-                    ? (JintStatement) new JintReturnStatement(_engine, new ReturnStatement((Expression) Function.Body))
-                    : new JintBlockStatement(_engine, (BlockStatement) Function.Body);
-
-                return _body;
+                _bodyExpression ??= JintExpression.Build(_engine, (Expression) Function.Body);
+                var jsValue = _bodyExpression?.GetValue() ?? Undefined.Instance;
+                return new Completion(CompletionType.Return, jsValue, null, Function.Body.Location);
             }
+
+            var blockStatement = (BlockStatement) Function.Body;
+            _bodyStatementList ??= new JintStatementList(_engine, blockStatement, blockStatement.Body);
+            return _bodyStatementList.Execute();
         }
 
         internal State Initialize(Engine engine, FunctionInstance functionInstance)

+ 17 - 18
Jint/Runtime/Interpreter/JintStatementList.cs

@@ -114,31 +114,30 @@ namespace Jint.Runtime.Interpreter
             List<VariableDeclaration> lexicalDeclarations)
         {
             var envRec = env._record;
+            var boundNames = new List<string>();
             for (var i = 0; i < lexicalDeclarations.Count; i++)
             {
                 var variableDeclaration = lexicalDeclarations[i];
-                ref readonly var nodeList = ref variableDeclaration.Declarations;
-                for (var j = 0; j < nodeList.Count; j++)
+                boundNames.Clear();
+                variableDeclaration.GetBoundNames(boundNames);
+                for (var j = 0; j < boundNames.Count; j++)
                 {
-                    var declaration = nodeList[j];
-                    if (declaration.Id is Identifier identifier)
+                    var dn = boundNames[j];
+                    if (variableDeclaration.Kind == VariableDeclarationKind.Const)
                     {
-                        if (variableDeclaration.Kind == VariableDeclarationKind.Const)
-                        {
-                            envRec.CreateImmutableBinding(identifier.Name, strict: true);
-                        }
-                        else
-                        {
-                            envRec.CreateMutableBinding(identifier.Name, canBeDeleted: false);
-                        }
+                        envRec.CreateImmutableBinding(dn, strict: true);
+                    }
+                    else
+                    {
+                        envRec.CreateMutableBinding(dn, canBeDeleted: false);
                     }
-                    // else if 
-                    /*  If d is a FunctionDeclaration, a GeneratorDeclaration, an AsyncFunctionDeclaration, or an AsyncGeneratorDeclaration, then
-                     * Let fn be the sole element of the BoundNames of d.
-                     * Let fo be the result of performing InstantiateFunctionObject for d with argument env.
-                     * Perform envRec.InitializeBinding(fn, fo).
-                     */
                 }
+
+                /*  If d is a FunctionDeclaration, a GeneratorDeclaration, an AsyncFunctionDeclaration, or an AsyncGeneratorDeclaration, then
+                 * Let fn be the sole element of the BoundNames of d.
+                 * Let fo be the result of performing InstantiateFunctionObject for d with argument env.
+                 * Perform envRec.InitializeBinding(fn, fo).
+                 */
             }
         }
     }

+ 1 - 0
Jint/Runtime/KnownKeys.cs

@@ -4,5 +4,6 @@ namespace Jint.Runtime
     {
         internal static readonly Key Arguments = "arguments";
         internal static readonly Key Eval = "eval";
+        internal static readonly Key Length = "length";
     }
 }

+ 7 - 5
Jint/Runtime/TypeConverter.cs

@@ -495,8 +495,10 @@ namespace Jint.Runtime
                 InternalTypes.Number => engine.Number.Construct(((JsNumber) value)._value),
                 InternalTypes.Integer => engine.Number.Construct(((JsNumber) value)._value),
                 InternalTypes.String => engine.String.Construct(value.ToString()),
-                InternalTypes.Symbol => engine.Symbol.Construct(((JsSymbol) value)),
-                _ => ExceptionHelper.ThrowTypeError<ObjectInstance>(engine)
+                InternalTypes.Symbol => engine.Symbol.Construct((JsSymbol) value),
+                InternalTypes.Null => ExceptionHelper.ThrowTypeError<ObjectInstance>(engine, "Cannot convert undefined or null to object"),
+                InternalTypes.Undefined => ExceptionHelper.ThrowTypeError<ObjectInstance>(engine, "Cannot convert undefined or null to object"),
+                _ => ExceptionHelper.ThrowTypeError<ObjectInstance>(engine, "Cannot convert given item to object")
             };
         }
         
@@ -506,7 +508,7 @@ namespace Jint.Runtime
             MemberExpression expression,
             string referenceName)
         {
-            if (o._type < InternalTypes.Boolean && (engine.Options.ReferenceResolver?.CheckCoercible(o)).GetValueOrDefault() != true)
+            if (o._type < InternalTypes.Boolean && !engine.Options.ReferenceResolver.CheckCoercible(o))
             {
                 ThrowTypeError(engine, o, expression, referenceName);
             }
@@ -518,8 +520,8 @@ namespace Jint.Runtime
             MemberExpression expression,
             string referencedName)
         {
-            referencedName ??= "The value";
-            var message = $"{referencedName} is {o}";
+            referencedName ??= "unknown";
+            var message = $"Cannot read property '{referencedName}' of {o}";
             throw new JavaScriptException(engine.TypeError, message).SetCallstack(engine, expression.Location);
         }
 

+ 3 - 4
appveyor.yml

@@ -27,7 +27,7 @@ test_script:
   - dotnet test .\Jint.Tests.Ecma\Jint.Tests.Ecma.csproj -c Release
   - dotnet test .\Jint.Tests.Test262\Jint.Tests.Test262.csproj -c Release
 artifacts:
-  - path: 'Jint\**\*.nupkg'
+  - path: 'Jint\**\*.*nupkg'
 deploy:  
   - provider: NuGet
     on:
@@ -50,6 +50,5 @@ deploy:
       branch: master
     server: https://www.nuget.org/api/v2/package
     api_key:
-      secure: qZ6R8U4mtBXFVRhhNLJyRz3bktF/jL5BvzrCQsXcn6ATRQ4YavFP3By8Sg4hYMH5
-    skip_symbols: true
-    artifact: /.*\.nupkg/
+      secure: yZBBCLlJTphpHCezRUxyDny1mBbDw7xFG/2Rwt21A8khKp6KJCxFEYx4k9IihOjO
+    artifact: /.*\.*nupkg/