Kaynağa Gözat

ES6 Object Literals (#605)

Marko Lahma 6 yıl önce
ebeveyn
işleme
753030e60a

+ 1 - 1
Jint.Benchmark/Jint.Benchmark.csproj

@@ -19,7 +19,7 @@
     <None Include="..\Jint.Tests.CommonScripts\Scripts\**" CopyToOutputDirectory="PreserveNewest" LinkBase="SunSpider" />
   </ItemGroup>
   <ItemGroup>
-    <PackageReference Include="BenchmarkDotNet" Version="0.11.2" />
+    <PackageReference Include="BenchmarkDotNet" Version="0.11.4" />
     <ProjectReference Include="..\Jint\Jint.csproj" />
     <PackageReference Include="Jurassic" Version="3.0.0-alpha2" />
     <PackageReference Include="Newtonsoft.Json" Version="12.0.1" />

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

@@ -7145,8 +7145,8 @@
     source: "ch11/11.1/11.1.5/11.1.5-3-s.js"
   },
   {
-    skip: false,
-    reason: "",
+    skip: true,
+    reason: "duplicate names allowed",
     source: "ch11/11.1/11.1.5/11.1.5-4-4-a-1-s.js"
   },
   {
@@ -7170,43 +7170,43 @@
     source: "ch11/11.1/11.1.5/11.1.5_4-4-a-3.js"
   },
   {
-    skip: false,
-    reason: "",
+    skip: true,
+    reason: "duplicate names now allowed",
     source: "ch11/11.1/11.1.5/11.1.5_4-4-b-1.js"
   },
   {
-    skip: false,
-    reason: "",
+    skip: true,
+    reason: "duplicate names now allowed",
     source: "ch11/11.1/11.1.5/11.1.5_4-4-b-2.js"
   },
   {
-    skip: false,
-    reason: "",
+    skip: true,
+    reason: "duplicate names now allowed",
     source: "ch11/11.1/11.1.5/11.1.5_4-4-c-1.js"
   },
   {
-    skip: false,
-    reason: "",
+    skip: true,
+    reason: "duplicate names now allowed",
     source: "ch11/11.1/11.1.5/11.1.5_4-4-c-2.js"
   },
   {
-    skip: false,
-    reason: "",
+    skip: true,
+    reason: "duplicate get get now allowed",
     source: "ch11/11.1/11.1.5/11.1.5_4-4-d-1.js"
   },
   {
-    skip: false,
-    reason: "",
+    skip: true,
+    reason: "duplicate set set allowed",
     source: "ch11/11.1/11.1.5/11.1.5_4-4-d-2.js"
   },
   {
-    skip: false,
-    reason: "",
+    skip: true,
+    reason: "duplicate property names now allowed",
     source: "ch11/11.1/11.1.5/11.1.5_4-4-d-3.js"
   },
   {
-    skip: false,
-    reason: "",
+    skip: true,
+    reason: "duplicate property names now allowed",
     source: "ch11/11.1/11.1.5/11.1.5_4-4-d-4.js"
   },
   {

+ 8 - 0
Jint.Tests.Test262/LanguageTests.cs

@@ -60,6 +60,14 @@ namespace Jint.Tests.Test262
             RunTestInternal(sourceFile);
         }
 
+        [Theory(DisplayName = "language\\expressions\\object")]
+        [MemberData(nameof(SourceFiles), "language\\expressions\\object", false)]
+        [MemberData(nameof(SourceFiles), "language\\expressions\\object", true, Skip = "Skipped")]
+        protected void ExpressionsObject(SourceFile sourceFile)
+        {
+            RunTestInternal(sourceFile);
+        }
+
         [Theory(DisplayName = "language\\expressions\\template-literal")]
         [MemberData(nameof(SourceFiles), "language\\expressions\\template-literal", false)]
         [MemberData(nameof(SourceFiles), "language\\expressions\\template-literal", true, Skip = "Skipped")]

+ 36 - 0
Jint.Tests.Test262/Test262Test.cs

@@ -102,6 +102,11 @@ namespace Jint.Tests.Test262
 
         protected void RunTestInternal(SourceFile sourceFile)
         {
+            if (sourceFile.Skip)
+            {
+                return;
+            }
+
             if (sourceFile.Code.IndexOf("onlyStrict", StringComparison.Ordinal) < 0)
             {
                 RunTestCode(sourceFile.Code, strict: false);
@@ -128,6 +133,23 @@ namespace Jint.Tests.Test262
 
                 var code = skip ? "" : File.ReadAllText(file);
 
+                var flags = Regex.Match(code, "flags: \\[(.+?)\\]");
+                if (flags.Success)
+                {
+                    var items = flags.Groups[1].Captures[0].Value.Split(",");
+                    foreach (var item in items.Select(x => x.Trim()))
+                    {
+                        switch (item)
+                        {
+                            // TODO implement
+                            case "async":
+                                skip = true;
+                                reason = "async not implemented";
+                                break;
+                        }
+                    }
+                }
+
                 var features = Regex.Match(code, "features: \\[(.+?)\\]");
                 if (features.Success)
                 {
@@ -209,10 +231,18 @@ namespace Jint.Tests.Test262
                                 skip = true;
                                 reason = "async-functions not implemented";
                                 break;
+                            case "async-iteration":
+                                skip = true;
+                                reason = "async not implemented";
+                                break;
                             case "new.target":
                                 skip = true;
                                 reason = "MetaProperty not implemented";
                                 break;
+                            case "super":
+                                skip = true;
+                                reason = "super not implemented";
+                                break;
                         }
                     }
                 }
@@ -223,6 +253,12 @@ namespace Jint.Tests.Test262
                     reason = "SpecialCasing.txt not implemented";
                 }
 
+                if (name.StartsWith("language/expressions/object/dstr-async-gen-meth-"))
+                {
+                    skip = true;
+                    reason = "Esprima problem, Unexpected token *";
+                }
+
                 if (file.EndsWith("tv-line-continuation.js")
                     || file.EndsWith("tv-line-terminator-sequence.js")
                     || file.EndsWith("special-characters.js"))

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

@@ -414,6 +414,16 @@
     "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"
+  },
 
   // class support
   {
@@ -496,6 +506,116 @@
     "source": "language/expressions/function/dstr-dflt-obj-ptrn-id-init-fn-name-class.js",
     "reason": "class not implemented"
   },
+  {
+    "source": "language/expressions/object/dstr-meth-dflt-obj-ptrn-id-init-fn-name-class.js",
+    "reason": "class not implemented"
+  },
+  {
+    "source": "language/expressions/object/dstr-meth-obj-ptrn-id-init-fn-name-class.js",
+    "reason": "class not implemented"
+  },
+  {
+    "source": "language/expressions/object/dstr-meth-ary-ptrn-elem-id-init-fn-name-class.js",
+    "reason": "class not implemented"
+  },
+  {
+    "source": "language/expressions/object/dstr-meth-dflt-ary-ptrn-elem-id-init-fn-name-class.js",
+    "reason": "class not implemented"
+  },
+  {
+    "source": "language/expressions/object/method-definition/name-invoke-ctor",
+    "reason": "class not implemented"
+  },
+  {
+    "source": "language/expressions/object/method-definition/name-invoke-ctor.js",
+    "reason": "class not implemented"
+  },
+  {
+    "source": "language/expressions/object/method-definition/name-prototype-prop.js",
+    "reason": "class not implemented"
+  },
+
+
+  {
+    "source": "language/expressions/object/accessor-name-computed-yield-id.js",
+    "reason": "accessor / yield not implemented"
+  },
+  {
+    "source": "language/expressions/object/accessor-name-computed.js",
+    "reason": "yield not implemented"
+  },
+  {
+    "source": "language/expressions/object/prop-dup-set-get-set.js",
+    "reason": "accessor not implemented"
+  },
+  {
+    "source": "language/expressions/object/accessor-name-computed-err-to-prop-key.js",
+    "reason": "accessor not implemented"
+  },
+  {
+    "source": "language/expressions/object/accessor-name-computed-err-unresolvable.js",
+    "reason": "accessor not implemented"
+  },
+  {
+    "source": "language/expressions/object/accessor-name-computed-in.js",
+    "reason": "accessor not implemented"
+  },
+  {
+    "source": "language/expressions/object/accessor-name-literal-numeric-leading-decimal.js",
+    "reason": "accessor not implemented"
+  },
+  {
+    "source": "language/expressions/object/accessor-name-literal-numeric-non-canonical.js",
+    "reason": "accessor not implemented"
+  },
+  {
+    "source": "language/expressions/object/fn-name-accessor-get.js",
+    "reason": "accessor not implemented"
+  },
+  {
+    "source": "language/expressions/object/fn-name-accessor-set.js",
+    "reason": "accessor not implemented"
+  },
+  {
+    "source": "language/expressions/object/method-definition/name-prop-name-yield-id.js",
+    "reason": "yield not implemented"
+  },
+
+
+  {
+    "source": "language/expressions/object/method.js",
+    "reason": "setPrototypeOf not implemented"
+  },
+  {
+    "source": "language/expressions/object/setter-super-prop.js",
+    "reason": "setPrototypeOf not implemented"
+  },
+  {
+    "source": "language/expressions/object/getter-super-prop.js",
+    "reason": "setPrototypeOf not implemented"
+  },
+
+
+  {
+    "source": "language/expressions/object/fn-name-arrow.js",
+    "reason": "symbols not identifiable in property name"
+  },
+  {
+    "source": "language/expressions/object/fn-name-cover.js",
+    "reason": "symbols not identifiable in property name"
+  },
+  {
+    "source": "language/expressions/object/fn-name-fn.js",
+    "reason": "symbols not identifiable in property name"
+  },
+  {
+    "source": "language/expressions/object/method-definition/fn-name-fn.js",
+    "reason": "symbols not identifiable in property name"
+  },
+  {
+    "source": "language/expressions/object/method-definition/name-name-prop-symbol.js",
+    "reason": "symbols not identifiable in property name"
+  },
 
 
   {
@@ -506,6 +626,14 @@
     "source": "language/expressions/function/scope-paramsbody-var-open.js",
     "reason": "not implemented: Creation of new variable environment for the function body (as distinct from that for the function's parameters)"
   },
+  {
+    "source": "language/expressions/object/scope-meth-paramsbody-var-open.js",
+    "reason": "not implemented: Creation of new variable environment for the function body (as distinct from that for the function's parameters)"
+  },
+  {
+    "source": "language/expressions/object/scope-setter-paramsbody-var-open.js",
+    "reason": "not implemented: Creation of new variable environment for the function body (as distinct from that for the function's parameters)"
+  },
 
   // Esprima problems
   
@@ -633,6 +761,86 @@
     "source": "language/expressions/function/params-trailing-comma-multiple.js",
     "reason": "Esprima problem"
   },
+  {
+    "source": "language/expressions/object/dstr-meth-dflt-obj-ptrn-rest-getter.js",
+    "reason": "Esprima problem"
+  },
+  {
+    "source": "language/expressions/object/dstr-meth-dflt-obj-ptrn-rest-val-obj.js",
+    "reason": "Esprima problem"
+  },
+  {
+    "source": "language/expressions/object/dstr-meth-obj-ptrn-rest-getter.js",
+    "reason": "Esprima problem"
+  },
+  {
+    "source": "language/expressions/object/dstr-meth-obj-ptrn-rest-val-obj.js",
+    "reason": "Esprima problem"
+  },
+  {
+    "source": "language/expressions/object/let-non-strict-access.js",
+    "reason": "Esprima problem"
+  },
+  {
+    "source": "language/expressions/object/method-definition/async-meth-dflt-params-abrupt.js",
+    "reason": "Esprima problem"
+  },
+  {
+    "source": "language/expressions/object/method-definition/async-meth-dflt-params-arg-val-not-undefined.js",
+    "reason": "Esprima problem"
+  },
+  {
+    "source": "language/expressions/object/method-definition/async-meth-dflt-params-ref-later.js",
+    "reason": "Esprima problem"
+  },
+  {
+    "source": "language/expressions/object/method-definition/async-meth-dflt-params-ref-prior.js",
+    "reason": "Esprima problem"
+  },
+  {
+    "source": "language/expressions/object/method-definition/async-meth-dflt-params-ref-self.js",
+    "reason": "Esprima problem"
+  },
+  {
+    "source": "language/expressions/object/dstr-meth-dflt-obj-ptrn-rest-skip-non-enumerable.js",
+    "reason": "Esprima problem"
+  },
+  {
+    "source": "language/expressions/object/dstr-meth-obj-ptrn-rest-skip-non-enumerable.js",
+    "reason": "Esprima problem"
+  },
+  {
+    "source": "language/expressions/object/let-non-strict-syntax.js",
+    "reason": "Esprima problem"
+  },
+  {
+    "source": "language/expressions/object/method-definition/meth-dflt-params-trailing-comma.js",
+    "reason": "Esprima problem"
+  },
+  {
+    "source": "language/expressions/object/method-definition/meth-params-trailing-comma-multiple.js",
+    "reason": "Esprima problem"
+  },
+  {
+    "source": "language/expressions/object/method-definition/meth-params-trailing-comma-single.js",
+    "reason": "Esprima problem"
+  },
+  {
+    "source": "language/expressions/object/method-definition/name-param-id-yield.js",
+    "reason": "Esprima problem"
+  },
+  {
+    "source": "language/expressions/object/yield-non-strict-access.js",
+    "reason": "Esprima problem"
+  },
+  {
+    "source": "language/expressions/object/yield-non-strict-syntax.js",
+    "reason": "Esprima problem"
+  },
+  {
+    "source": "language/expressions/object/method-definition/object-method-returns-promise.js",
+    "reason": "Esprima problem"
+  },
   {
     "source": "language/expressions/function/params-trailing-comma-single.js",
     "reason": "Esprima problem"

+ 1 - 1
Jint/Engine.cs

@@ -37,7 +37,7 @@ namespace Jint
         private static readonly ParserOptions DefaultParserOptions = new ParserOptions
         {
             AdaptRegexp = true,
-            Tolerant = false,
+            Tolerant = true,
             Loc = true
         };
 

+ 14 - 6
Jint/EsprimaExtensions.cs

@@ -3,12 +3,13 @@ using System.Runtime.CompilerServices;
 using Esprima.Ast;
 using Jint.Native.Symbol;
 using Jint.Runtime;
+using Jint.Runtime.Interpreter.Expressions;
 
 namespace Jint
 {
     public static class EsprimaExtensions
     {
-        public static string GetKey<T>(this T expression) where T : Expression
+        public static string GetKey<T>(this T expression, Engine engine) where T : class, Expression
         {
             if (expression is Literal literal)
             {
@@ -22,8 +23,8 @@ namespace Jint
 
             if (expression is StaticMemberExpression staticMemberExpression)
             {
-                var obj = staticMemberExpression.Object.GetKey();
-                var property = staticMemberExpression.Property.GetKey();
+                var obj = staticMemberExpression.Object.GetKey(engine);
+                var property = staticMemberExpression.Property.GetKey(engine);
 
                 if (obj == "Symbol")
                 {
@@ -38,14 +39,21 @@ namespace Jint
                 }
             }
 
-            return ExceptionHelper.ThrowArgumentException<string>("Unable to extract correct key");
+            if (expression.Type == Nodes.CallExpression
+                || expression.Type == Nodes.BinaryExpression
+                || expression.Type == Nodes.UpdateExpression)
+            {
+                return Convert.ToString(JintExpression.Build(engine, expression).GetValue());
+            }
+
+            return ExceptionHelper.ThrowArgumentException<string>("Unable to extract correct key, node type: " + expression.Type);
         }
 
         [MethodImpl(MethodImplOptions.AggressiveInlining)]
-        internal static bool IsFunctionWithName(this INode node)
+        internal static bool IsFunctionWithName<T>(this T node) where T : class, INode
         {
             var type = node.Type;
-            return type == Nodes.FunctionExpression || type == Nodes.ArrowFunctionExpression;
+            return type == Nodes.FunctionExpression || type == Nodes.ArrowFunctionExpression || type == Nodes.ArrowParameterPlaceHolder;
         }
     }
 }

+ 1 - 1
Jint/Jint.csproj

@@ -7,6 +7,6 @@
     <LangVersion>latest</LangVersion>
   </PropertyGroup>
   <ItemGroup>
-    <PackageReference Include="Esprima" Version="1.0.0-beta-1182" />
+    <PackageReference Include="Esprima" Version="1.0.0-beta-1184" />
   </ItemGroup>
 </Project>

+ 2 - 3
Jint/Native/Function/ArrowFunctionInstance.cs

@@ -13,7 +13,7 @@ namespace Jint.Native.Function
         private readonly JsValue _thisBinding;
 
         /// <summary>
-        /// http://www.ecma-international.org/ecma-262/5.1/#sec-13.2
+        /// http://www.ecma-international.org/ecma-262/6.0/#sec-arrow-function-definitions
         /// </summary>
         public ArrowFunctionInstance(
             Engine engine,
@@ -81,8 +81,7 @@ namespace Jint.Native.Function
 
                     if (result.Type == CompletionType.Throw)
                     {
-                        var ex = new JavaScriptException(value).SetCallstack(_engine, result.Location);
-                        throw ex;
+                        ExceptionHelper.ThrowJavaScriptException(_engine, value, result);
                     }
 
                     if (result.Type == CompletionType.Return)

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

@@ -10,7 +10,7 @@ namespace Jint.Native.Function
     {
         private const string PropertyNamePrototype = "prototype";
         private const int PropertyNamePrototypeLength = 9;
-        protected PropertyDescriptor _prototype;
+        protected internal PropertyDescriptor _prototype;
 
         private const string PropertyNameLength = "length";
         private const int PropertyNameLengthLength = 6;
@@ -22,7 +22,7 @@ namespace Jint.Native.Function
 
         protected readonly LexicalEnvironment _scope;
         protected internal readonly string[] _formalParameters;
-        private readonly bool _strict;
+        protected readonly bool _strict;
 
         protected FunctionInstance(
             Engine engine,

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

@@ -119,7 +119,7 @@ namespace Jint.Native.Function
             JsValue[] values = ArrayExt.Empty<JsValue>();
             if (arguments.Length > 1)
             {
-                values = _engine._jsValueArrayPool.RentArray(arguments.Length - 1);
+                values = new JsValue[arguments.Length - 1];
                 System.Array.Copy(arguments, 1, values, 0, arguments.Length - 1);
             }
 

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

@@ -17,7 +17,7 @@ namespace Jint.Native.Function
         /// http://www.ecma-international.org/ecma-262/5.1/#sec-13.2
         /// </summary>
         public ScriptFunctionInstance(
-            Engine engine, 
+            Engine engine,
             IFunction functionDeclaration,
             LexicalEnvironment scope,
             bool strict)
@@ -67,7 +67,7 @@ namespace Jint.Native.Function
         /// <returns></returns>
         public override JsValue Call(JsValue thisArg, JsValue[] arguments)
         {
-            var strict = Strict || _engine._isStrict;
+            var strict = _strict || _engine._isStrict;
             using (new StrictModeScope(strict, true))
             {
                 // setup new execution context http://www.ecma-international.org/ecma-262/5.1/#sec-10.4.3
@@ -102,9 +102,9 @@ namespace Jint.Native.Function
                         arguments);
 
                     var result = _function._body.Execute();
-                    
+
                     var value = result.GetValueOrDefault();
-                    
+
                     if (argumentInstanceRented)
                     {
                         _engine.ExecutionContext.LexicalEnvironment?._record?.FunctionWasCalled();
@@ -113,8 +113,7 @@ namespace Jint.Native.Function
 
                     if (result.Type == CompletionType.Throw)
                     {
-                        var ex = new JavaScriptException(value).SetCallstack(_engine, result.Location);
-                        throw ex;
+                        ExceptionHelper.ThrowJavaScriptException(_engine, value, result);
                     }
 
                     if (result.Type == CompletionType.Return)
@@ -139,6 +138,7 @@ namespace Jint.Native.Function
         public ObjectInstance Construct(JsValue[] arguments)
         {
             var proto = Get("prototype").TryCast<ObjectInstance>();
+
             var obj = new ObjectInstance(_engine)
             {
                 Extensible = true,

+ 6 - 1
Jint/Native/JsString.cs

@@ -209,7 +209,12 @@ namespace Jint.Native
             {
                 if (other is ConcatenatedString cs)
                 {
-                    return _stringBuilder.Equals(cs._stringBuilder);
+                    if (_stringBuilder != null && cs._stringBuilder != null)
+                    {
+                        return _stringBuilder.Equals(cs._stringBuilder);
+                    }
+
+                    return ToString() == cs.ToString();
                 }
 
                 if (other is JsString jsString)

+ 11 - 7
Jint/Native/JsValue.cs

@@ -227,17 +227,21 @@ namespace Jint.Native
 
         [Pure]
         [MethodImpl(MethodImplOptions.AggressiveInlining)]
-        public T TryCast<T>(Action<JsValue> fail = null) where T : class
+        public T TryCast<T>() where T : class
         {
-            if (_type == Types.Object)
+            return this as T;
+        }
+
+        [Pure]
+        [MethodImpl(MethodImplOptions.AggressiveInlining)]
+        public T TryCast<T>(Action<JsValue> fail) where T : class
+        {
+            if (this is T o)
             {
-                if (this is T o)
-                {
-                    return o;
-                }
+                return o;
             }
 
-            fail?.Invoke(this);
+            fail.Invoke(this);
 
             return null;
         }

+ 3 - 2
Jint/Runtime/ExceptionHelper.cs

@@ -1,4 +1,5 @@
 using System;
+using Jint.Native;
 using Jint.Runtime.CallStack;
 using Jint.Runtime.References;
 
@@ -135,9 +136,9 @@ namespace Jint.Runtime
             throw new InvalidOperationException(message);
         }
 
-        public static void ThrowJavaScriptException(string message)
+        public static void ThrowJavaScriptException(Engine engine, JsValue value, Completion result)
         {
-            throw new JavaScriptException("TypeError");
+            throw new JavaScriptException(value).SetCallstack(engine, result.Location);
         }
 
         public static void ThrowRecursionDepthOverflowException(JintCallStack currentStack, string currentExpressionReference)

+ 2 - 1
Jint/Runtime/Interpreter/Expressions/JintExpression.cs

@@ -32,6 +32,7 @@ namespace Jint.Runtime.Interpreter.Expressions
             return _engine.GetValue(Evaluate(), true);
         }
 
+        [MethodImpl(MethodImplOptions.AggressiveInlining)]
         public object Evaluate()
         {
             _engine._lastSyntaxNode = _expression;
@@ -336,7 +337,7 @@ namespace Jint.Runtime.Interpreter.Expressions
             }
         }
 
-        protected void BuildArguments(JintExpression[] jintExpressions, JsValue[] targetArray)
+        protected static void BuildArguments(JintExpression[] jintExpressions, JsValue[] targetArray)
         {
             for (var i = 0; i < jintExpressions.Length; i++)
             {

+ 37 - 66
Jint/Runtime/Interpreter/Expressions/JintObjectExpression.cs

@@ -1,9 +1,9 @@
+using System;
 using System.Collections.Generic;
 using System.Threading;
 using Esprima.Ast;
 using Jint.Collections;
 using Jint.Native.Function;
-using Jint.Native.Object;
 using Jint.Runtime.Descriptors;
 using Jint.Runtime.Descriptors.Specialized;
 
@@ -48,15 +48,29 @@ namespace Jint.Runtime.Interpreter.Expressions
             for (var i = 0; i < _properties.Length; i++)
             {
                 var property = expression.Properties[i];
-                var propName = property.Key.GetKey();
+                string propName = null;
+
+                if (property.Key is Literal literal)
+                {
+                    propName = literal.Value as string ?? Convert.ToString(literal.Value, provider: null);
+                }
+
+                if (property.Key is Identifier identifier)
+                {
+                    propName = identifier.Name;
+                }
+
                 _properties[i] = new ObjectProperty
                 {
-                    _name = propName, _value = property
+                    _name = propName,
+                    _value = property
                 };
 
                 if (property.Kind == PropertyKind.Init || property.Kind == PropertyKind.Data)
                 {
-                    _valueExpressions[i] = Build(_engine, (Expression) property.Value);
+                    var propertyValue = (Expression) property.Value;
+                    _valueExpressions[i] = Build(_engine, propertyValue);
+                    _canBuildFast &= !propertyValue.IsFunctionWithName();
                 }
                 else
                 {
@@ -64,6 +78,7 @@ namespace Jint.Runtime.Interpreter.Expressions
                 }
 
                 _canBuildFast &= propertyNames.Add(propName);
+                _canBuildFast &= propName != null;
             }
         }
 
@@ -87,7 +102,8 @@ namespace Jint.Runtime.Interpreter.Expressions
             for (var i = 0; i < _properties.Length; i++)
             {
                 var objectProperty = _properties[i];
-                var propValue = _valueExpressions[i].GetValue();
+                var valueExpression = _valueExpressions[i];
+                var propValue = valueExpression.GetValue();
                 properties[objectProperty._name] = new PropertyDescriptor(propValue, PropertyFlag.ConfigurableEnumerableWritable);
             }
 
@@ -99,15 +115,12 @@ namespace Jint.Runtime.Interpreter.Expressions
         {
             var obj = _engine.Object.Construct(System.Math.Max(2, _properties.Length));
             bool isStrictModeCode = StrictModeScope.IsStrictModeCode;
+
             for (var i = 0; i < _properties.Length; i++)
             {
                 var objectProperty = _properties[i];
                 var property = objectProperty._value;
-                var propName = objectProperty._name;
-                if (!obj._properties.TryGetValue(propName, out var previous))
-                {
-                    previous = PropertyDescriptor.Undefined;
-                }
+                var propName = objectProperty._name ?? objectProperty._value.Key.GetKey(_engine);
 
                 PropertyDescriptor propDesc;
 
@@ -115,22 +128,25 @@ namespace Jint.Runtime.Interpreter.Expressions
                 {
                     var expr = _valueExpressions[i];
                     var propValue = expr.GetValue();
+                    if (expr._expression.IsFunctionWithName())
+                    {
+                        var functionInstance = (FunctionInstance) propValue;
+                        functionInstance.SetFunctionName(objectProperty._name);
+                    }
                     propDesc = new PropertyDescriptor(propValue, PropertyFlag.ConfigurableEnumerableWritable);
                 }
                 else if (property.Kind == PropertyKind.Get || property.Kind == PropertyKind.Set)
                 {
                     var function = property.Value as IFunction ?? ExceptionHelper.ThrowSyntaxError<IFunction>(_engine);
 
-                    ScriptFunctionInstance functionInstance;
-                    using (new StrictModeScope(function.Strict))
-                    {
-                        functionInstance = new ScriptFunctionInstance(
-                            _engine,
-                            function,
-                            _engine.ExecutionContext.LexicalEnvironment,
-                            isStrictModeCode
-                        );
-                    }
+                    var functionInstance = new ScriptFunctionInstance(
+                        _engine,
+                        function,
+                        _engine.ExecutionContext.LexicalEnvironment,
+                        isStrictModeCode
+                    );
+                    functionInstance.SetFunctionName(objectProperty._name);
+                    functionInstance._prototype = null;
 
                     propDesc = new GetSetPropertyDescriptor(
                         get: property.Kind == PropertyKind.Get ? functionInstance : null,
@@ -142,55 +158,10 @@ namespace Jint.Runtime.Interpreter.Expressions
                     return ExceptionHelper.ThrowArgumentOutOfRangeException<object>();
                 }
 
-                if (previous != PropertyDescriptor.Undefined)
-                {
-                    DefinePropertySlow(isStrictModeCode, previous, propDesc, obj, propName);
-                }
-                else
-                {
-                    // do faster direct set
-                    obj._properties[propName] = propDesc;
-                }
+                obj.DefineOwnProperty(propName, propDesc, false);
             }
 
             return obj;
         }
-
-        private void DefinePropertySlow(
-            bool isStrictModeCode,
-            PropertyDescriptor previous,
-            PropertyDescriptor propDesc, ObjectInstance obj, string propName)
-        {
-            var previousIsDataDescriptor = previous.IsDataDescriptor();
-            if (isStrictModeCode && previousIsDataDescriptor && propDesc.IsDataDescriptor())
-            {
-                ExceptionHelper.ThrowSyntaxError(_engine);
-            }
-
-            if (previousIsDataDescriptor && propDesc.IsAccessorDescriptor())
-            {
-                ExceptionHelper.ThrowSyntaxError(_engine);
-            }
-
-            if (previous.IsAccessorDescriptor() && propDesc.IsDataDescriptor())
-            {
-                ExceptionHelper.ThrowSyntaxError(_engine);
-            }
-
-            if (previous.IsAccessorDescriptor() && propDesc.IsAccessorDescriptor())
-            {
-                if (!ReferenceEquals(propDesc.Set, null) && !ReferenceEquals(previous.Set, null))
-                {
-                    ExceptionHelper.ThrowSyntaxError(_engine);
-                }
-
-                if (!ReferenceEquals(propDesc.Get, null) && !ReferenceEquals(previous.Get, null))
-                {
-                    ExceptionHelper.ThrowSyntaxError(_engine);
-                }
-            }
-
-            obj.DefineOwnProperty(propName, propDesc, false);
-        }
     }
 }

+ 11 - 1
Jint/Runtime/Interpreter/JintFunctionDefinition.cs

@@ -33,7 +33,17 @@ namespace Jint.Runtime.Interpreter
             }
             else
             {
-                bodyStatement = (BlockStatement) function.Body;
+                // Esprima doesn't detect strict at the moment for
+                // language/expressions/object/method-definition/name-invoke-fn-strict.js
+                var blockStatement = (BlockStatement) function.Body;
+                for (int i = 0; i < blockStatement.Body.Count; ++i)
+                {
+                    if (blockStatement.Body[i] is Directive d && d.Directiv == "use strict")
+                    {
+                        _strict = true;
+                    }
+                }
+                bodyStatement = blockStatement;
             }
 
             _body = JintStatement.Build(engine, bodyStatement);

+ 21 - 16
Jint/Runtime/Interpreter/Statements/JintStatement.cs

@@ -1,4 +1,5 @@
-using Esprima;
+using System.Runtime.CompilerServices;
+using Esprima;
 using Esprima.Ast;
 using Jint.Runtime.Interpreter.Expressions;
 
@@ -6,19 +7,30 @@ namespace Jint.Runtime.Interpreter.Statements
 {
     internal abstract class JintStatement<T> : JintStatement where T : Statement
     {
-        // require sub-classes to set to false explicitly to skip virtual call
-        protected bool _initialized = true;
+        protected readonly T _statement;
+
+        protected JintStatement(Engine engine, T statement) : base(engine, statement)
+        {
+            _statement = statement;
+        }
+    }
 
+    internal abstract class JintStatement
+    {
         protected readonly Engine _engine;
-        protected readonly T _statement;
+        private readonly Statement _statement;
 
-        protected JintStatement(Engine engine, T statement)
+        // require sub-classes to set to false explicitly to skip virtual call
+        protected bool _initialized = true;
+
+        protected JintStatement(Engine engine, Statement statement)
         {
             _engine = engine;
             _statement = statement;
         }
 
-        public sealed override Completion Execute()
+        [MethodImpl(MethodImplOptions.AggressiveInlining)]
+        public Completion Execute()
         {
             _engine._lastSyntaxNode = _statement;
 
@@ -36,7 +48,9 @@ namespace Jint.Runtime.Interpreter.Statements
             return ExecuteInternal();
         }
 
-        public override Location Location => _statement.Location;
+        protected abstract Completion ExecuteInternal();
+
+        public Location Location => _statement.Location;
 
         /// <summary>
         /// Opportunity to build one-time structures and caching based on lexical context.
@@ -44,15 +58,6 @@ namespace Jint.Runtime.Interpreter.Statements
         protected virtual void Initialize()
         {
         }
-    }
-
-    internal abstract class JintStatement
-    {
-        public abstract Location Location { get; }
-
-        public abstract Completion Execute();
-
-        protected abstract Completion ExecuteInternal();
 
         protected internal static JintStatement Build(Engine engine, Statement statement)
         {

+ 1 - 1
Jint/Runtime/JavaScriptException.cs

@@ -52,7 +52,7 @@ namespace Jint.Runtime
                             sb.Builder.Append(", ");
                         var arg = cse.CallExpression.Arguments[index];
                         if (arg is Expression pke)
-                            sb.Builder.Append(pke.GetKey());
+                            sb.Builder.Append(pke.GetKey(engine));
                         else
                             sb.Builder.Append(arg);
                     }

+ 1 - 1
README.md

@@ -154,7 +154,7 @@ This example is using French as the default culture.
 ES6 features which are being implemented:
 - [x] [arrows](https://github.com/lukehoban/es6features/blob/master/README.md#arrows)
 - [ ] [classes](https://github.com/lukehoban/es6features/blob/master/README.md#classes)
-- [ ] [enhanced object literals](https://github.com/lukehoban/es6features/blob/master/README.md#enhanced-object-literals)
+- [x] [enhanced object literals](https://github.com/lukehoban/es6features/blob/master/README.md#enhanced-object-literals)
 - [x] [template strings](https://github.com/lukehoban/es6features/blob/master/README.md#template-strings)
 - [x] [destructuring](https://github.com/lukehoban/es6features/blob/master/README.md#destructuring)
 - [x] [default + rest + spread](https://github.com/lukehoban/es6features/blob/master/README.md#default--rest--spread)