瀏覽代碼

Fix TaggedTemplate issues (#1324)

Marko Lahma 2 年之前
父節點
當前提交
3cde7c9a4c

+ 1 - 10
Jint.Tests.Test262/Test262Harness.settings.json

@@ -162,6 +162,7 @@
     "language/expressions/object/method-definition/async-super-call-param.js",
     "language/expressions/object/method-definition/async-super-call-param.js",
     "language/expressions/object/method-definition/name-super-prop-param.js",
     "language/expressions/object/method-definition/name-super-prop-param.js",
     "language/expressions/optional-chaining/member-expression.js",
     "language/expressions/optional-chaining/member-expression.js",
+    "language/expressions/tagged-template/invalid-escape-sequences.js",
     "language/statements/for-of/dstr-obj-id-init-let.js",
     "language/statements/for-of/dstr-obj-id-init-let.js",
     "language/statements/for/head-lhs-let.js",
     "language/statements/for/head-lhs-let.js",
     "language/expressions/object/yield-non-strict-access.js",
     "language/expressions/object/yield-non-strict-access.js",
@@ -430,16 +431,6 @@
     "language/expressions/prefix-increment/operator-prefix-increment-x-calls-putvalue-lhs-newvalue--1.js",
     "language/expressions/prefix-increment/operator-prefix-increment-x-calls-putvalue-lhs-newvalue--1.js",
     "language/expressions/prefix-increment/operator-prefix-increment-x-calls-putvalue-lhs-newvalue-.js",
     "language/expressions/prefix-increment/operator-prefix-increment-x-calls-putvalue-lhs-newvalue-.js",
     "language/expressions/super/call-proto-not-ctor.js",
     "language/expressions/super/call-proto-not-ctor.js",
-    "language/expressions/tagged-template/cache-different-functions-same-site.js",
-    "language/expressions/tagged-template/cache-eval-inner-function.js",
-    "language/expressions/tagged-template/cache-same-site-top-level.js",
-    "language/expressions/tagged-template/cache-same-site.js",
-    "language/expressions/tagged-template/invalid-escape-sequences.js",
-    "language/expressions/tagged-template/member-expression-context.js",
-    "language/expressions/tagged-template/template-object-frozen-non-strict.js",
-    "language/expressions/tagged-template/template-object-frozen-strict.js",
-    "language/expressions/tagged-template/template-object-template-map.js",
-    "language/expressions/tagged-template/template-object.js",
     "language/expressions/template-literal/tv-line-continuation.js",
     "language/expressions/template-literal/tv-line-continuation.js",
     "language/function-code/eval-param-env-with-computed-key.js",
     "language/function-code/eval-param-env-with-computed-key.js",
     "language/function-code/eval-param-env-with-prop-initializer.js",
     "language/function-code/eval-param-env-with-prop-initializer.js",

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

@@ -389,7 +389,7 @@ namespace Jint.Native.Object
                 return arguments.At(0);
                 return arguments.At(0);
             }
             }
 
 
-            var status = SetIntegrityLevel(o, IntegrityLevel.Sealed);
+            var status = o.SetIntegrityLevel(IntegrityLevel.Sealed);
 
 
             if (!status)
             if (!status)
             {
             {
@@ -409,7 +409,7 @@ namespace Jint.Native.Object
                 return arguments.At(0);
                 return arguments.At(0);
             }
             }
 
 
-            var status = SetIntegrityLevel(o, IntegrityLevel.Frozen);
+            var status = o.SetIntegrityLevel(IntegrityLevel.Frozen);
 
 
             if (!status)
             if (!status)
             {
             {
@@ -419,64 +419,12 @@ namespace Jint.Native.Object
             return o;
             return o;
         }
         }
 
 
-        /// <summary>
-        /// https://tc39.es/ecma262/#sec-setintegritylevel
-        /// </summary>
-        private static bool SetIntegrityLevel(ObjectInstance o, IntegrityLevel level)
-        {
-            var status = o.PreventExtensions();
-            if (!status)
-            {
-                return false;
-            }
-
-            var keys = o.GetOwnPropertyKeys();
-            if (level == IntegrityLevel.Sealed)
-            {
-                for (var i = 0; i < keys.Count; i++)
-                {
-                    var k = keys[i];
-                    o.DefinePropertyOrThrow(k, new PropertyDescriptor { Configurable = false });
-                }
-            }
-            else
-            {
-                for (var i = 0; i < keys.Count; i++)
-                {
-                    var k = keys[i];
-                    var currentDesc = o.GetOwnProperty(k);
-                    if (currentDesc != PropertyDescriptor.Undefined)
-                    {
-                        PropertyDescriptor desc;
-                        if (currentDesc.IsAccessorDescriptor())
-                        {
-                            desc = new PropertyDescriptor { Configurable = false };
-                        }
-                        else
-                        {
-                            desc = new PropertyDescriptor { Configurable = false, Writable = false };
-                        }
-
-                        o.DefinePropertyOrThrow(k, desc);
-                    }
-                }
-            }
-
-            return true;
-        }
-
-        private enum IntegrityLevel
-        {
-            Sealed,
-            Frozen
-        }
-
         /// <summary>
         /// <summary>
         /// https://tc39.es/ecma262/#sec-object.preventextensions
         /// https://tc39.es/ecma262/#sec-object.preventextensions
         /// </summary>
         /// </summary>
         private JsValue PreventExtensions(JsValue thisObject, JsValue[] arguments)
         private JsValue PreventExtensions(JsValue thisObject, JsValue[] arguments)
         {
         {
-            if (!(arguments.At(0) is ObjectInstance o))
+            if (arguments.At(0) is not ObjectInstance o)
             {
             {
                 return arguments.At(0);
                 return arguments.At(0);
             }
             }

+ 52 - 0
Jint/Native/Object/ObjectInstance.cs

@@ -1421,5 +1421,57 @@ namespace Jint.Native.Object
 
 
             return min;
             return min;
         }
         }
+
+        /// <summary>
+        /// https://tc39.es/ecma262/#sec-setintegritylevel
+        /// </summary>
+        internal bool SetIntegrityLevel(IntegrityLevel level)
+        {
+            var status = PreventExtensions();
+            if (!status)
+            {
+                return false;
+            }
+
+            var keys = GetOwnPropertyKeys();
+            if (level == IntegrityLevel.Sealed)
+            {
+                for (var i = 0; i < keys.Count; i++)
+                {
+                    var k = keys[i];
+                    DefinePropertyOrThrow(k, new PropertyDescriptor { Configurable = false });
+                }
+            }
+            else
+            {
+                for (var i = 0; i < keys.Count; i++)
+                {
+                    var k = keys[i];
+                    var currentDesc = GetOwnProperty(k);
+                    if (currentDesc != PropertyDescriptor.Undefined)
+                    {
+                        PropertyDescriptor desc;
+                        if (currentDesc.IsAccessorDescriptor())
+                        {
+                            desc = new PropertyDescriptor { Configurable = false };
+                        }
+                        else
+                        {
+                            desc = new PropertyDescriptor { Configurable = false, Writable = false };
+                        }
+
+                        DefinePropertyOrThrow(k, desc);
+                    }
+                }
+            }
+
+            return true;
+        }
+
+        internal enum IntegrityLevel
+        {
+            Sealed,
+            Frozen
+        }
     }
     }
 }
 }

+ 70 - 50
Jint/Runtime/Interpreter/Expressions/JintTaggedTemplateExpression.cs

@@ -1,75 +1,95 @@
 using Esprima.Ast;
 using Esprima.Ast;
 using Jint.Native;
 using Jint.Native;
 using Jint.Native.Array;
 using Jint.Native.Array;
+using Jint.Native.Object;
 using Jint.Runtime.Descriptors;
 using Jint.Runtime.Descriptors;
+using Jint.Runtime.References;
 
 
-namespace Jint.Runtime.Interpreter.Expressions
+namespace Jint.Runtime.Interpreter.Expressions;
+
+internal sealed class JintTaggedTemplateExpression : JintExpression
 {
 {
-    internal sealed class JintTaggedTemplateExpression : JintExpression
+    internal static readonly JsString PropertyRaw = new JsString("raw");
+
+    private JintExpression _tagIdentifier = null!;
+    private JintTemplateLiteralExpression _quasi = null!;
+
+    public JintTaggedTemplateExpression(TaggedTemplateExpression expression) : base(expression)
     {
     {
-        internal static  readonly JsString PropertyRaw = new JsString("raw");
+        _initialized = false;
+    }
 
 
-        private readonly TaggedTemplateExpression _taggedTemplateExpression;
-        private JintExpression _tagIdentifier = null!;
-        private JintTemplateLiteralExpression _quasi = null!;
+    protected override void Initialize(EvaluationContext context)
+    {
+        var taggedTemplateExpression = (TaggedTemplateExpression) _expression;
+        _tagIdentifier = Build(taggedTemplateExpression.Tag);
+        _quasi = new JintTemplateLiteralExpression(taggedTemplateExpression.Quasi);
+        _quasi.DoInitialize();
+    }
 
 
-        public JintTaggedTemplateExpression(TaggedTemplateExpression expression) : base(expression)
-        {
-            _taggedTemplateExpression = expression;
-            _initialized = false;
-        }
+    protected override object EvaluateInternal(EvaluationContext context)
+    {
+        var engine = context.Engine;
 
 
-        protected override void Initialize(EvaluationContext context)
+        var identifier = _tagIdentifier.Evaluate(context);
+        var tagger = engine.GetValue(identifier) as ICallable;
+        if (tagger is null)
         {
         {
-            _tagIdentifier = Build(_taggedTemplateExpression.Tag);
-            _quasi = new JintTemplateLiteralExpression(_taggedTemplateExpression.Quasi);
-            _quasi.DoInitialize();
+            ExceptionHelper.ThrowTypeError(engine.Realm, "Argument must be callable");
         }
         }
 
 
-        protected override object EvaluateInternal(EvaluationContext context)
-        {
-            var engine = context.Engine;
-            var tagger = engine.GetValue(_tagIdentifier.GetValue(context)) as ICallable;
-            if (tagger is null)
-            {
-                ExceptionHelper.ThrowTypeError(engine.Realm, "Argument must be callable");
-            }
+        var expressions = _quasi._expressions;
 
 
-            var expressions = _quasi._expressions;
+        var args = engine._jsValueArrayPool.RentArray(expressions.Length + 1);
 
 
-            var args = engine._jsValueArrayPool.RentArray(expressions.Length + 1);
+        var template = GetTemplateObject(context);
+        args[0] = template;
 
 
-            var template = GetTemplateObject(context);
-            args[0] = template;
+        for (var i = 0; i < expressions.Length; ++i)
+        {
+            args[i + 1] = expressions[i].GetValue(context);
+        }
+
+        var thisObject = identifier is Reference reference && reference.IsPropertyReference()
+            ? reference.GetBase()
+            : JsValue.Undefined;
 
 
-            for (int i = 0; i < expressions.Length; ++i)
-            {
-                args[i + 1] = expressions[i].GetValue(context);
-            }
+        var result = tagger.Call(thisObject, args);
 
 
-            var result = tagger.Call(JsValue.Undefined, args);
-            engine._jsValueArrayPool.ReturnArray(args);
+        engine._jsValueArrayPool.ReturnArray(args);
 
 
-            return result;
+        return result;
+    }
+
+    /// <summary>
+    /// https://www.ecma-international.org/ecma-262/6.0/#sec-gettemplateobject
+    /// </summary>
+    private ArrayInstance GetTemplateObject(EvaluationContext context)
+    {
+        var realm = context.Engine.Realm;
+        var templateRegistry = realm._templateMap;
+        if (templateRegistry.TryGetValue(this._expression, out var cached))
+        {
+            return cached;
         }
         }
 
 
-        /// <summary>
-        /// https://www.ecma-international.org/ecma-262/6.0/#sec-gettemplateobject
-        /// </summary>
-        private ArrayInstance GetTemplateObject(EvaluationContext context)
+        var count = (uint) _quasi._templateLiteralExpression.Quasis.Count;
+        var template = context.Engine.Realm.Intrinsics.Array.ArrayCreate(count);
+        var rawObj = context.Engine.Realm.Intrinsics.Array.ArrayCreate(count);
+        for (uint i = 0; i < _quasi._templateLiteralExpression.Quasis.Count; ++i)
         {
         {
-            var count = (uint) _quasi._templateLiteralExpression.Quasis.Count;
-            var template = context.Engine.Realm.Intrinsics.Array.ArrayCreate(count);
-            var rawObj = context.Engine.Realm.Intrinsics.Array.ArrayCreate(count);
-            for (uint i = 0; i < _quasi._templateLiteralExpression.Quasis.Count; ++i)
-            {
-                var templateElementValue = _quasi._templateLiteralExpression.Quasis[(int) i].Value;
-                template.SetIndexValue(i, templateElementValue.Cooked, updateLength: false);
-                rawObj.SetIndexValue(i, templateElementValue.Raw, updateLength: false);
-            }
-
-            template.DefineOwnProperty(PropertyRaw, new PropertyDescriptor(rawObj, PropertyFlag.AllForbidden));
-            return template;
+            var templateElementValue = _quasi._templateLiteralExpression.Quasis[(int) i].Value;
+            template.SetIndexValue(i, templateElementValue.Cooked, updateLength: false);
+            rawObj.SetIndexValue(i, templateElementValue.Raw, updateLength: false);
         }
         }
+
+        rawObj.SetIntegrityLevel(ObjectInstance.IntegrityLevel.Frozen);
+        template.DefineOwnProperty(PropertyRaw, new PropertyDescriptor(rawObj, PropertyFlag.OnlyWritable));
+
+        template.SetIntegrityLevel(ObjectInstance.IntegrityLevel.Frozen);
+
+        realm._templateMap[_expression] = template;
+
+        return template;
     }
     }
 }
 }

+ 5 - 1
Jint/Runtime/Realm.cs

@@ -1,3 +1,5 @@
+using Esprima.Ast;
+using Jint.Native.Array;
 using Jint.Native.Object;
 using Jint.Native.Object;
 using Jint.Runtime.Environments;
 using Jint.Runtime.Environments;
 
 
@@ -5,8 +7,10 @@ namespace Jint.Runtime
 {
 {
     public sealed class Realm
     public sealed class Realm
     {
     {
+        internal readonly Dictionary<Node, ArrayInstance> _templateMap = new();
 
 
-// helps when debugging which nested realm we are in...
+
+        // helps when debugging which nested realm we are in...
 #if DEBUG
 #if DEBUG
         private static int globalId = 1;
         private static int globalId = 1;