Object.prototype.toString is not spec-perfect
authorshvaikalesh@gmail.com <shvaikalesh@gmail.com@268f45cc-cd09-0410-ab3c-d52691b4dbfc>
Tue, 5 May 2020 11:33:21 +0000 (11:33 +0000)
committershvaikalesh@gmail.com <shvaikalesh@gmail.com@268f45cc-cd09-0410-ab3c-d52691b4dbfc>
Tue, 5 May 2020 11:33:21 +0000 (11:33 +0000)
https://bugs.webkit.org/show_bug.cgi?id=199138

Reviewed by Darin Adler and Keith Miller.

JSTests:

* ChakraCore.yaml: Skip a test as `global` now has @@toStringTag.
* ChakraCore/test/LetConst/delete.baseline: Removed.
* stress/internal-promise-constructor-not-confusing.js: Use @isPromise.
* stress/object-get-own-property-symbols.js: Adjust test as `global` now has @@toStringTag.
* test262/expectations.yaml: Mark 6 test cases as passing.

LayoutTests/imported/w3c:

* web-platform-tests/WebIDL/ecmascript-binding/class-string-interface.any-expected.txt:
* web-platform-tests/WebIDL/ecmascript-binding/class-string-interface.any.worker-expected.txt:
* web-platform-tests/WebIDL/ecmascript-binding/class-string-iterator-prototype-object.any-expected.txt:
* web-platform-tests/WebIDL/ecmascript-binding/class-string-iterator-prototype-object.any.worker-expected.txt:

Source/JavaScriptCore:

Before ES6, Object.prototype.toString relied only on internal [[Class]] slot. Starting with ES6,
Object.prototype.toString checks for a handful of internal slots, mimicing [[Class]], to ensure
backwards compatibility for pre-ES6 instances. Newly-added built-ins provide @@toStringTag for
the method to use.

Before this change, Object.prototype.toString in JSC relied on className() a.k.a [[Class]] for
all instances. For (almost all) new built-ins, it was overriden by toStringName() returning
"Object", while @@toStringTag was set to correct value. This is quite an error-prone approach
and observable spec discrepancy if @@toStringTag is deleted or set to a non-string.

This change eliminates the above-mentioned discrepancy and fixes Object.prototype.toString
to return "[object Function]" for callable Proxy objects, aligning JSC with the spec [1], V8,
and SpiderMonkey.

For Object.prototype.toString to work through DebuggerScope and JSProxy, we perform all checks
in JSObject::toStringName(). Given that isArray() may throw a TypeError [2], we invoke
toStringName() before @@toStringTag lookup to accomodate revoked Proxy case.

Also, this patch defines @@toStringTag for WebAssembly namespace object (to match Chrome),
JSC shell, and ConsoleObject.

[1]: https://tc39.es/ecma262/#sec-object.prototype.tostring
[2]: https://tc39.es/ecma262/#sec-isarray (step 3.a)

* jsc.cpp:
* runtime/BigIntObject.cpp:
(JSC::BigIntObject::toStringName): Deleted.
* runtime/BigIntObject.h:
* runtime/BooleanObject.cpp:
(JSC::BooleanObject::toStringName):
* runtime/BooleanObject.h:
* runtime/ConsoleObject.cpp:
(JSC::ConsoleObject::finishCreation):
* runtime/DateInstance.cpp:
(JSC::DateInstance::toStringName):
* runtime/DateInstance.h:
* runtime/ErrorInstance.cpp:
(JSC::ErrorInstance::toStringName):
* runtime/ErrorInstance.h:
* runtime/JSArrayBufferView.cpp:
(JSC::JSArrayBufferView::toStringName): Deleted.
* runtime/JSArrayBufferView.h:
* runtime/JSMap.cpp:
(JSC::JSMap::toStringName): Deleted.
* runtime/JSMap.h:
* runtime/JSObject.cpp:
(JSC::JSObject::toStringName):
* runtime/JSSet.cpp:
(JSC::JSSet::toStringName): Deleted.
* runtime/JSSet.h:
* runtime/JSWeakMap.cpp:
(JSC::JSWeakMap::toStringName): Deleted.
* runtime/JSWeakMap.h:
* runtime/JSWeakObjectRef.cpp:
(JSC::JSWeakObjectRef::toStringName): Deleted.
* runtime/JSWeakObjectRef.h:
* runtime/JSWeakSet.cpp:
(JSC::JSWeakSet::toStringName): Deleted.
* runtime/JSWeakSet.h:
* runtime/NumberObject.cpp:
(JSC::NumberObject::toStringName):
* runtime/NumberObject.h:
* runtime/ObjectPrototype.cpp:
(JSC::objectProtoFuncToString):
* runtime/ProxyObject.cpp:
(JSC::ProxyObject::toStringName): Deleted.
* runtime/ProxyObject.h:
* runtime/RegExpObject.cpp:
(JSC::RegExpObject::toStringName):
* runtime/RegExpObject.h:
* runtime/StringObject.cpp:
(JSC::StringObject::toStringName):
* runtime/StringObject.h:
* runtime/SymbolObject.cpp:
(JSC::SymbolObject::toStringName): Deleted.
* runtime/SymbolObject.h:
* wasm/js/JSWebAssembly.cpp:
(JSC::JSWebAssembly::finishCreation):

Source/WebCore:

This patch defines @@toStringTag symbols for all WebIDL prototypes, including
interfaces that are not exposed, as required by the spec [1].

With updated JSObject::toStringName() and @@toStringTag symbols added in r260992,
className() and toStringName() methods of JSDOMConstructorBase can be safely removed.

[1]: https://heycam.github.io/webidl/#dfn-class-string

Tests: imported/w3c/web-platform-tests/WebIDL/ecmascript-binding/class-string-interface.any.js
       imported/w3c/web-platform-tests/WebIDL/ecmascript-binding/class-string-iterator-prototype-object.any.js

* bindings/js/JSDOMConstructorBase.cpp:
(WebCore::JSDOMConstructorBase::className): Deleted.
(WebCore::JSDOMConstructorBase::toStringName): Deleted.
* bindings/js/JSDOMConstructorBase.h:
* bindings/scripts/CodeGeneratorJS.pm:
(GenerateImplementation):
(GeneratePrototypeDeclaration):
* bindings/scripts/test/JS/JSTestGlobalObject.cpp:
(WebCore::JSTestGlobalObjectPrototype::finishCreation):

Tools:

* TestWebKitAPI/Tests/JavaScriptCore/glib/TestJSC.cpp:

git-svn-id: http://svn.webkit.org/repository/webkit/trunk@261159 268f45cc-cd09-0410-ab3c-d52691b4dbfc

54 files changed:
JSTests/ChakraCore.yaml
JSTests/ChakraCore/test/LetConst/delete.baseline [deleted file]
JSTests/ChangeLog
JSTests/stress/internal-promise-constructor-not-confusing.js
JSTests/stress/object-get-own-property-symbols.js
JSTests/test262/expectations.yaml
LayoutTests/imported/w3c/ChangeLog
LayoutTests/imported/w3c/web-platform-tests/WebIDL/ecmascript-binding/class-string-interface.any-expected.txt
LayoutTests/imported/w3c/web-platform-tests/WebIDL/ecmascript-binding/class-string-interface.any.worker-expected.txt
LayoutTests/imported/w3c/web-platform-tests/WebIDL/ecmascript-binding/class-string-iterator-prototype-object.any-expected.txt
LayoutTests/imported/w3c/web-platform-tests/WebIDL/ecmascript-binding/class-string-iterator-prototype-object.any.worker-expected.txt
Source/JavaScriptCore/ChangeLog
Source/JavaScriptCore/jsc.cpp
Source/JavaScriptCore/runtime/BigIntObject.cpp
Source/JavaScriptCore/runtime/BigIntObject.h
Source/JavaScriptCore/runtime/BooleanObject.cpp
Source/JavaScriptCore/runtime/BooleanObject.h
Source/JavaScriptCore/runtime/ConsoleObject.cpp
Source/JavaScriptCore/runtime/DateInstance.cpp
Source/JavaScriptCore/runtime/DateInstance.h
Source/JavaScriptCore/runtime/ErrorInstance.cpp
Source/JavaScriptCore/runtime/ErrorInstance.h
Source/JavaScriptCore/runtime/JSArrayBufferView.cpp
Source/JavaScriptCore/runtime/JSArrayBufferView.h
Source/JavaScriptCore/runtime/JSMap.cpp
Source/JavaScriptCore/runtime/JSMap.h
Source/JavaScriptCore/runtime/JSObject.cpp
Source/JavaScriptCore/runtime/JSSet.cpp
Source/JavaScriptCore/runtime/JSSet.h
Source/JavaScriptCore/runtime/JSWeakMap.cpp
Source/JavaScriptCore/runtime/JSWeakMap.h
Source/JavaScriptCore/runtime/JSWeakObjectRef.cpp
Source/JavaScriptCore/runtime/JSWeakObjectRef.h
Source/JavaScriptCore/runtime/JSWeakSet.cpp
Source/JavaScriptCore/runtime/JSWeakSet.h
Source/JavaScriptCore/runtime/NumberObject.cpp
Source/JavaScriptCore/runtime/NumberObject.h
Source/JavaScriptCore/runtime/ObjectPrototype.cpp
Source/JavaScriptCore/runtime/ProxyObject.cpp
Source/JavaScriptCore/runtime/ProxyObject.h
Source/JavaScriptCore/runtime/RegExpObject.cpp
Source/JavaScriptCore/runtime/RegExpObject.h
Source/JavaScriptCore/runtime/StringObject.cpp
Source/JavaScriptCore/runtime/StringObject.h
Source/JavaScriptCore/runtime/SymbolObject.cpp
Source/JavaScriptCore/runtime/SymbolObject.h
Source/JavaScriptCore/wasm/js/JSWebAssembly.cpp
Source/WebCore/ChangeLog
Source/WebCore/bindings/js/JSDOMConstructorBase.cpp
Source/WebCore/bindings/js/JSDOMConstructorBase.h
Source/WebCore/bindings/scripts/CodeGeneratorJS.pm
Source/WebCore/bindings/scripts/test/JS/JSTestGlobalObject.cpp
Tools/ChangeLog
Tools/TestWebKitAPI/Tests/JavaScriptCore/glib/TestJSC.cpp

index f838d1a..7f1aea6 100644 (file)
 - path: ChakraCore/test/LetConst/defer5.js
   cmd: runChakra :baseline, "ReferenceError", "defer5.baseline-jsc", []
 - path: ChakraCore/test/LetConst/delete.js
-  cmd: runChakra :baseline, "NoException", "delete.baseline", []
+  # The test should use Reflect.ownKeys as `this` may have symbol properties.
+  cmd: runChakra :skipDueToOutdatedOrBadTest, "NoException", "", []
 - path: ChakraCore/test/LetConst/dop.js
   cmd: runChakra :baseline, "NoException", "dop.baseline-jsc", []
 - path: ChakraCore/test/LetConst/dop1.js
diff --git a/JSTests/ChakraCore/test/LetConst/delete.baseline b/JSTests/ChakraCore/test/LetConst/delete.baseline
deleted file mode 100644 (file)
index 09628b1..0000000
+++ /dev/null
@@ -1,4 +0,0 @@
-20
-let x
-let x
-PASS
index 4c4e67e..e634f7b 100644 (file)
@@ -1,3 +1,16 @@
+2020-05-05  Alexey Shvayka  <shvaikalesh@gmail.com>
+
+        Object.prototype.toString is not spec-perfect
+        https://bugs.webkit.org/show_bug.cgi?id=199138
+
+        Reviewed by Darin Adler and Keith Miller.
+
+        * ChakraCore.yaml: Skip a test as `global` now has @@toStringTag.
+        * ChakraCore/test/LetConst/delete.baseline: Removed.
+        * stress/internal-promise-constructor-not-confusing.js: Use @isPromise.
+        * stress/object-get-own-property-symbols.js: Adjust test as `global` now has @@toStringTag.
+        * test262/expectations.yaml: Mark 6 test cases as passing.
+
 2020-05-04  Yusuke Suzuki  <ysuzuki@apple.com>
 
         [JSC] Implement BigInt.asIntN and BigInt.asUintN
index b994d49..fccf24d 100644 (file)
@@ -7,19 +7,26 @@ var InternalPromise = $vm.createBuiltin(`(function () {
     return @InternalPromise;
 })`)();
 
+var isPromise = $vm.createBuiltin(`(function (p) {
+    return @isPromise(p);
+})`);
+
 function DerivedPromise() { }
 
 for (var i = 0; i < 1e4; ++i) {
     var promise = Reflect.construct(InternalPromise, [function (resolve) { resolve(42); }], DerivedPromise);
-    shouldBe(promise.toString(), `[object InternalPromise]`);
+    shouldBe(promise.toString(), `[object Object]`);
+    shouldBe(isPromise(promise), true);
 }
 drainMicrotasks();
 for (var i = 0; i < 1e4; ++i) {
     var promise = Reflect.construct(Promise, [function (resolve) { resolve(42); }], DerivedPromise);
-    shouldBe(promise.toString(), `[object Promise]`);
+    shouldBe(promise.toString(), `[object Object]`);
+    shouldBe(isPromise(promise), true);
 }
 drainMicrotasks();
 for (var i = 0; i < 1e4; ++i) {
     var promise = Reflect.construct(InternalPromise, [function (resolve) { resolve(42); }], DerivedPromise);
-    shouldBe(promise.toString(), `[object InternalPromise]`);
+    shouldBe(promise.toString(), `[object Object]`);
+    shouldBe(isPromise(promise), true);
 }
index 40e93d8..16f3aab 100644 (file)
@@ -3,8 +3,9 @@
 var global = (Function("return this")());
 
 // private names for privileged code should not be exposed.
-if (Object.getOwnPropertySymbols(global).length !== 0)
-    throw "Error: bad value " + Object.getOwnPropertySymbols(global).length;
+var globalSymbols = Object.getOwnPropertySymbols(global).filter(s => s !== Symbol.toStringTag);
+if (globalSymbols.length !== 0)
+    throw "Error: bad value " + globalSymbols.length;
 
 var object = {};
 var symbol = Symbol("Cocoa");
index 44f48fb..47f4df5 100644 (file)
@@ -970,15 +970,6 @@ test/built-ins/Object/internals/DefineOwnProperty/consistent-value-regexp-dollar
 test/built-ins/Object/keys/order-after-define-property.js:
   default: 'Test262Error: Expected [b, a] and [a, b] to have the same contents. '
   strict mode: 'Test262Error: Expected [b, a] and [a, b] to have the same contents. '
-test/built-ins/Object/prototype/toString/proxy-function.js:
-  default: 'Test262Error: function proxy Expected SameValue(«[object Object]», «[object Function]») to be true'
-  strict mode: 'Test262Error: function proxy Expected SameValue(«[object Object]», «[object Function]») to be true'
-test/built-ins/Object/prototype/toString/symbol-tag-non-str-builtin.js:
-  default: 'Test262Error: Expected SameValue(«[object Math]», «[object Object]») to be true'
-  strict mode: 'Test262Error: Expected SameValue(«[object Math]», «[object Object]») to be true'
-test/built-ins/Object/prototype/toString/symbol-tag-non-str-proxy-function.js:
-  default: 'Test262Error: generator function proxy without Symbol.toStringTag Expected SameValue(«[object Object]», «[object Function]») to be true'
-  strict mode: 'Test262Error: generator function proxy without Symbol.toStringTag Expected SameValue(«[object Object]», «[object Function]») to be true'
 test/built-ins/Object/values/order-after-define-property.js:
   default: 'Test262Error: Expected [b, a] and [a, b] to have the same contents. '
   strict mode: 'Test262Error: Expected [b, a] and [a, b] to have the same contents. '
index 604c0e3..da21743 100644 (file)
@@ -1,3 +1,15 @@
+2020-05-05  Alexey Shvayka  <shvaikalesh@gmail.com>
+
+        Object.prototype.toString is not spec-perfect
+        https://bugs.webkit.org/show_bug.cgi?id=199138
+
+        Reviewed by Darin Adler and Keith Miller.
+
+        * web-platform-tests/WebIDL/ecmascript-binding/class-string-interface.any-expected.txt:
+        * web-platform-tests/WebIDL/ecmascript-binding/class-string-interface.any.worker-expected.txt:
+        * web-platform-tests/WebIDL/ecmascript-binding/class-string-iterator-prototype-object.any-expected.txt:
+        * web-platform-tests/WebIDL/ecmascript-binding/class-string-iterator-prototype-object.any.worker-expected.txt:
+
 2020-05-04  Yusuke Suzuki  <ysuzuki@apple.com>
 
         [JSC] Add @@toStringTag to WebAssembly.Global
index 6caef71..cf543d1 100644 (file)
@@ -5,6 +5,6 @@ PASS Object.prototype.toString applied to the prototype
 PASS Object.prototype.toString applied to an instance 
 PASS Object.prototype.toString applied after modifying the prototype's @@toStringTag 
 PASS Object.prototype.toString applied to the instance after modifying the instance's @@toStringTag 
-FAIL Object.prototype.toString applied to a null-prototype instance assert_equals: expected "[object Object]" but got "[object Blob]"
-FAIL Object.prototype.toString applied after deleting @@toStringTag assert_equals: prototype expected "[object Object]" but got "[object Blob]"
+PASS Object.prototype.toString applied to a null-prototype instance 
+PASS Object.prototype.toString applied after deleting @@toStringTag 
 
index 6caef71..cf543d1 100644 (file)
@@ -5,6 +5,6 @@ PASS Object.prototype.toString applied to the prototype
 PASS Object.prototype.toString applied to an instance 
 PASS Object.prototype.toString applied after modifying the prototype's @@toStringTag 
 PASS Object.prototype.toString applied to the instance after modifying the instance's @@toStringTag 
-FAIL Object.prototype.toString applied to a null-prototype instance assert_equals: expected "[object Object]" but got "[object Blob]"
-FAIL Object.prototype.toString applied after deleting @@toStringTag assert_equals: prototype expected "[object Object]" but got "[object Blob]"
+PASS Object.prototype.toString applied to a null-prototype instance 
+PASS Object.prototype.toString applied after deleting @@toStringTag 
 
index 3b23541..4c80ba5 100644 (file)
@@ -3,5 +3,5 @@ PASS @@toStringTag exists with the appropriate descriptor
 PASS Object.prototype.toString 
 PASS Object.prototype.toString applied after modifying @@toStringTag 
 FAIL Object.prototype.toString applied after nulling the prototype assert_equals: expected "[object Object]" but got "[object URLSearchParams Iterator]"
-FAIL Object.prototype.toString applied after deleting @@toStringTag assert_equals: prototype expected "[object Object]" but got "[object URLSearchParams Iterator]"
+PASS Object.prototype.toString applied after deleting @@toStringTag 
 
index 3b23541..4c80ba5 100644 (file)
@@ -3,5 +3,5 @@ PASS @@toStringTag exists with the appropriate descriptor
 PASS Object.prototype.toString 
 PASS Object.prototype.toString applied after modifying @@toStringTag 
 FAIL Object.prototype.toString applied after nulling the prototype assert_equals: expected "[object Object]" but got "[object URLSearchParams Iterator]"
-FAIL Object.prototype.toString applied after deleting @@toStringTag assert_equals: prototype expected "[object Object]" but got "[object URLSearchParams Iterator]"
+PASS Object.prototype.toString applied after deleting @@toStringTag 
 
index 9f5a81e..69434d0 100644 (file)
@@ -1,3 +1,89 @@
+2020-05-05  Alexey Shvayka  <shvaikalesh@gmail.com>
+
+        Object.prototype.toString is not spec-perfect
+        https://bugs.webkit.org/show_bug.cgi?id=199138
+
+        Reviewed by Darin Adler and Keith Miller.
+
+        Before ES6, Object.prototype.toString relied only on internal [[Class]] slot. Starting with ES6,
+        Object.prototype.toString checks for a handful of internal slots, mimicing [[Class]], to ensure
+        backwards compatibility for pre-ES6 instances. Newly-added built-ins provide @@toStringTag for
+        the method to use.
+
+        Before this change, Object.prototype.toString in JSC relied on className() a.k.a [[Class]] for
+        all instances. For (almost all) new built-ins, it was overriden by toStringName() returning
+        "Object", while @@toStringTag was set to correct value. This is quite an error-prone approach
+        and observable spec discrepancy if @@toStringTag is deleted or set to a non-string.
+
+        This change eliminates the above-mentioned discrepancy and fixes Object.prototype.toString
+        to return "[object Function]" for callable Proxy objects, aligning JSC with the spec [1], V8,
+        and SpiderMonkey.
+
+        For Object.prototype.toString to work through DebuggerScope and JSProxy, we perform all checks
+        in JSObject::toStringName(). Given that isArray() may throw a TypeError [2], we invoke
+        toStringName() before @@toStringTag lookup to accomodate revoked Proxy case.
+
+        Also, this patch defines @@toStringTag for WebAssembly namespace object (to match Chrome),
+        JSC shell, and ConsoleObject.
+
+        [1]: https://tc39.es/ecma262/#sec-object.prototype.tostring
+        [2]: https://tc39.es/ecma262/#sec-isarray (step 3.a)
+
+        * jsc.cpp:
+        * runtime/BigIntObject.cpp:
+        (JSC::BigIntObject::toStringName): Deleted.
+        * runtime/BigIntObject.h:
+        * runtime/BooleanObject.cpp:
+        (JSC::BooleanObject::toStringName):
+        * runtime/BooleanObject.h:
+        * runtime/ConsoleObject.cpp:
+        (JSC::ConsoleObject::finishCreation):
+        * runtime/DateInstance.cpp:
+        (JSC::DateInstance::toStringName):
+        * runtime/DateInstance.h:
+        * runtime/ErrorInstance.cpp:
+        (JSC::ErrorInstance::toStringName):
+        * runtime/ErrorInstance.h:
+        * runtime/JSArrayBufferView.cpp:
+        (JSC::JSArrayBufferView::toStringName): Deleted.
+        * runtime/JSArrayBufferView.h:
+        * runtime/JSMap.cpp:
+        (JSC::JSMap::toStringName): Deleted.
+        * runtime/JSMap.h:
+        * runtime/JSObject.cpp:
+        (JSC::JSObject::toStringName):
+        * runtime/JSSet.cpp:
+        (JSC::JSSet::toStringName): Deleted.
+        * runtime/JSSet.h:
+        * runtime/JSWeakMap.cpp:
+        (JSC::JSWeakMap::toStringName): Deleted.
+        * runtime/JSWeakMap.h:
+        * runtime/JSWeakObjectRef.cpp:
+        (JSC::JSWeakObjectRef::toStringName): Deleted.
+        * runtime/JSWeakObjectRef.h:
+        * runtime/JSWeakSet.cpp:
+        (JSC::JSWeakSet::toStringName): Deleted.
+        * runtime/JSWeakSet.h:
+        * runtime/NumberObject.cpp:
+        (JSC::NumberObject::toStringName):
+        * runtime/NumberObject.h:
+        * runtime/ObjectPrototype.cpp:
+        (JSC::objectProtoFuncToString):
+        * runtime/ProxyObject.cpp:
+        (JSC::ProxyObject::toStringName): Deleted.
+        * runtime/ProxyObject.h:
+        * runtime/RegExpObject.cpp:
+        (JSC::RegExpObject::toStringName):
+        * runtime/RegExpObject.h:
+        * runtime/StringObject.cpp:
+        (JSC::StringObject::toStringName):
+        * runtime/StringObject.h:
+        * runtime/SymbolObject.cpp:
+        (JSC::SymbolObject::toStringName): Deleted.
+        * runtime/SymbolObject.h:
+        * wasm/js/JSWebAssembly.cpp:
+        (JSC::JSWebAssembly::finishCreation):
+
 2020-05-04  Yusuke Suzuki  <ysuzuki@apple.com>
 
         [JSC] Implement BigInt.asIntN and BigInt.asUintN
index 47d21d5..438b444 100644 (file)
@@ -494,6 +494,7 @@ private:
     void finishCreation(VM& vm, const Vector<String>& arguments)
     {
         Base::finishCreation(vm);
+        JSC_TO_STRING_TAG_WITHOUT_TRANSITION();
 
         addFunction(vm, "debug", functionDebug, 1);
         addFunction(vm, "describe", functionDescribe, 1);
index e61982b..311f6da 100644 (file)
@@ -56,11 +56,6 @@ void BigIntObject::finishCreation(VM& vm, JSValue bigInt)
     setInternalValue(vm, bigInt);
 }
 
-String BigIntObject::toStringName(const JSObject*, JSGlobalObject*)
-{
-    return "Object"_s;
-}
-
 JSValue BigIntObject::defaultValue(const JSObject* object, JSGlobalObject*, PreferredPrimitiveType)
 {
     const BigIntObject* bigIntObject = jsCast<const BigIntObject*>(object);
index e259567..46bf5ba 100644 (file)
@@ -53,8 +53,6 @@ public:
 
     static JSValue defaultValue(const JSObject*, JSGlobalObject*, PreferredPrimitiveType);
 
-    static String toStringName(const JSObject*, JSGlobalObject*);
-
 private:
     JS_EXPORT_PRIVATE void finishCreation(VM&, JSValue);
     JS_EXPORT_PRIVATE BigIntObject(VM&, Structure*);
index 7de5deb..56c6759 100644 (file)
@@ -41,4 +41,9 @@ void BooleanObject::finishCreation(VM& vm)
     ASSERT(inherits(vm, info()));
 }
 
+String BooleanObject::toStringName(const JSObject*, JSGlobalObject*)
+{
+    return "Boolean"_s;
+}
+
 } // namespace JSC
index 4ff82f5..8aa0917 100644 (file)
@@ -51,6 +51,8 @@ public:
     {
         return Structure::create(vm, globalObject, prototype, TypeInfo(ObjectType, StructureFlags), info());
     }
+
+    static String toStringName(const JSObject*, JSGlobalObject*);
 };
 static_assert(sizeof(BooleanObject) == sizeof(JSWrapperObject));
 
index cc80af6..615b57e 100644 (file)
@@ -117,6 +117,8 @@ void ConsoleObject::finishCreation(VM& vm, JSGlobalObject* globalObject)
     JSC_NATIVE_FUNCTION_WITHOUT_TRANSITION("record", consoleProtoFuncRecord, static_cast<unsigned>(PropertyAttribute::None), 0);
     JSC_NATIVE_FUNCTION_WITHOUT_TRANSITION("recordEnd", consoleProtoFuncRecordEnd, static_cast<unsigned>(PropertyAttribute::None), 0);
     JSC_NATIVE_FUNCTION_WITHOUT_TRANSITION("screenshot", consoleProtoFuncScreenshot, static_cast<unsigned>(PropertyAttribute::None), 0);
+
+    JSC_TO_STRING_TAG_WITHOUT_TRANSITION();
 }
 
 static String valueToStringWithUndefinedOrNullCheck(JSGlobalObject* globalObject, JSValue value)
index 915854b..e68b0de 100644 (file)
@@ -50,6 +50,11 @@ void DateInstance::finishCreation(VM& vm, double time)
     m_internalNumber = timeClip(time);
 }
 
+String DateInstance::toStringName(const JSObject*, JSGlobalObject*)
+{
+    return "Date"_s;
+}
+
 const GregorianDateTime* DateInstance::calculateGregorianDateTime(VM& vm) const
 {
     double milli = internalNumber();
index d53eb3e..c36ec7d 100644 (file)
@@ -54,6 +54,7 @@ public:
         return instance;
     }
 
+    static String toStringName(const JSObject*, JSGlobalObject*);
     double internalNumber() const { return m_internalNumber; }
     void setInternalNumber(double value) { m_internalNumber = value; }
 
index c21884f..d8ace9d 100644 (file)
@@ -311,4 +311,9 @@ bool ErrorInstance::deleteProperty(JSCell* cell, JSGlobalObject* globalObject, P
     return Base::deleteProperty(thisObject, globalObject, propertyName, slot);
 }
 
+String ErrorInstance::toStringName(const JSObject*, JSGlobalObject*)
+{
+    return "Error"_s;
+}
+
 } // namespace JSC
index 5b3253d..a6386e3 100644 (file)
@@ -98,6 +98,7 @@ protected:
     static bool defineOwnProperty(JSObject*, JSGlobalObject*, PropertyName, const PropertyDescriptor&, bool shouldThrow);
     static bool put(JSCell*, JSGlobalObject*, PropertyName, JSValue, PutPropertySlot&);
     static bool deleteProperty(JSCell*, JSGlobalObject*, PropertyName, DeletePropertySlot&);
+    static String toStringName(const JSObject*, JSGlobalObject*);
 
     void computeErrorInfo(VM&);
 
index 38ed60d..bb09c8d 100644 (file)
@@ -42,11 +42,6 @@ const ClassInfo JSArrayBufferView::s_info = {
     "ArrayBufferView", &Base::s_info, nullptr, nullptr, CREATE_METHOD_TABLE(JSArrayBufferView)
 };
 
-String JSArrayBufferView::toStringName(const JSObject*, JSGlobalObject*)
-{
-    return "Object"_s;
-}
-
 JSArrayBufferView::ConstructionContext::ConstructionContext(
     Structure* structure, uint32_t length, void* vector)
     : m_structure(structure)
index dd2e9c3..e4c18cd 100644 (file)
@@ -212,8 +212,6 @@ protected:
 
     ArrayBuffer* existingBufferInButterfly();
 
-    static String toStringName(const JSObject*, JSGlobalObject*);
-
     VectorPtr m_vector;
     uint32_t m_length;
     TypedArrayMode m_mode;
index 41450f8..40eced9 100644 (file)
@@ -33,11 +33,6 @@ namespace JSC {
 
 const ClassInfo JSMap::s_info = { "Map", &Base::s_info, nullptr, nullptr, CREATE_METHOD_TABLE(JSMap) };
 
-String JSMap::toStringName(const JSObject*, JSGlobalObject*)
-{
-    return "Object"_s;
-}
-
 JSMap* JSMap::clone(JSGlobalObject* globalObject, VM& vm, Structure* structure)
 {
     JSMap* instance = new (NotNull, allocateCell<JSMap>(vm.heap)) JSMap(vm, structure);
index c28c1ee..c8bd1e4 100644 (file)
@@ -68,8 +68,6 @@ private:
         : Base(vm, structure)
     {
     }
-
-    static String toStringName(const JSObject*, JSGlobalObject*);
 };
 
 static_assert(std::is_final<JSMap>::value, "Required for JSType based casting");
index 1bf22c7..3b81e6a 100644 (file)
@@ -24,6 +24,7 @@
 #include "config.h"
 #include "JSObject.h"
 
+#include "ArrayConstructor.h"
 #include "ButterflyInlines.h"
 #include "CatchScope.h"
 #include "CustomGetterSetter.h"
@@ -519,9 +520,16 @@ String JSObject::className(const JSObject* object, VM& vm)
 String JSObject::toStringName(const JSObject* object, JSGlobalObject* globalObject)
 {
     VM& vm = globalObject->vm();
-    const ClassInfo* info = object->classInfo(vm);
-    ASSERT(info);
-    return info->className;
+    auto scope = DECLARE_THROW_SCOPE(vm);
+    bool objectIsArray = isArray(globalObject, object);
+    RETURN_IF_EXCEPTION(scope, String());
+    if (objectIsArray)
+        return "Array"_s;
+    if (TypeInfo::isArgumentsType(object->type()))
+        return "Arguments"_s;
+    if (const_cast<JSObject*>(object)->isCallable(vm))
+        return "Function"_s;
+    return "Object"_s;
 }
 
 String JSObject::calculatedClassName(JSObject* object)
index 73ea789..3953097 100644 (file)
@@ -33,11 +33,6 @@ namespace JSC {
 
 const ClassInfo JSSet::s_info = { "Set", &Base::s_info, nullptr, nullptr, CREATE_METHOD_TABLE(JSSet) };
 
-String JSSet::toStringName(const JSObject*, JSGlobalObject*)
-{
-    return "Object"_s;
-}
-
 JSSet* JSSet::clone(JSGlobalObject* globalObject, VM& vm, Structure* structure)
 {
     JSSet* instance = new (NotNull, allocateCell<JSSet>(vm.heap)) JSSet(vm, structure);
index 5a15d23..8d13dff 100644 (file)
@@ -73,8 +73,6 @@ private:
         : Base(vm, structure, sizeHint)
     {
     }
-
-    static String toStringName(const JSObject*, JSGlobalObject*);
 };
 
 static_assert(std::is_final<JSSet>::value, "Required for JSType based casting");
index 352c413..41ebd8f 100644 (file)
@@ -32,9 +32,4 @@ namespace JSC {
 
 const ClassInfo JSWeakMap::s_info = { "WeakMap", &Base::s_info, nullptr, nullptr, CREATE_METHOD_TABLE(JSWeakMap) };
 
-String JSWeakMap::toStringName(const JSObject*, JSGlobalObject*)
-{
-    return "Object"_s;
-}
-
 }
index b29efbe..160de56 100644 (file)
@@ -58,8 +58,6 @@ private:
         : Base(vm, structure)
     {
     }
-
-    static String toStringName(const JSObject*, JSGlobalObject*);
 };
 
 static_assert(std::is_final<JSWeakMap>::value, "Required for JSType based casting");
index 3754c93..51f9d43 100644 (file)
@@ -57,10 +57,5 @@ void JSWeakObjectRef::finalizeUnconditionally(VM& vm)
         m_value.clear();
 }
 
-String JSWeakObjectRef::toStringName(const JSC::JSObject*, JSGlobalObject*)
-{
-    return "Object"_s;
-}
-
 }
 
index 3e4b9a5..bef57aa 100644 (file)
@@ -75,8 +75,6 @@ private:
 
     JS_EXPORT_PRIVATE void finishCreation(VM&, JSObject* value);
 
-    static String toStringName(const JSObject*, JSGlobalObject*);
-
     uintptr_t m_lastAccessVersion;
     WriteBarrier<JSObject> m_value;
 };
index 2796112..bfdd94e 100644 (file)
@@ -32,9 +32,4 @@ namespace JSC {
 
 const ClassInfo JSWeakSet::s_info = { "WeakSet", &Base::s_info, nullptr, nullptr, CREATE_METHOD_TABLE(JSWeakSet) };
 
-String JSWeakSet::toStringName(const JSC::JSObject*, JSGlobalObject*)
-{
-    return "Object"_s;
-}
-
 }
index 7622bd6..4c222d3 100644 (file)
@@ -53,8 +53,6 @@ private:
         : Base(vm, structure)
     {
     }
-
-    static String toStringName(const JSObject*, JSGlobalObject*);
 };
 
 static_assert(std::is_final<JSWeakSet>::value, "Required for JSType based casting");
index e804f49..e150dda 100644 (file)
@@ -44,6 +44,11 @@ void NumberObject::finishCreation(VM& vm)
     ASSERT(type() == NumberObjectType);
 }
 
+String NumberObject::toStringName(const JSObject*, JSGlobalObject*)
+{
+    return "Number"_s;
+}
+
 NumberObject* constructNumber(JSGlobalObject* globalObject, JSValue number)
 {
     NumberObject* object = NumberObject::create(globalObject->vm(), globalObject->numberObjectStructure());
index 1409fba..3f64e5e 100644 (file)
@@ -51,6 +51,8 @@ public:
     {
         return Structure::create(vm, globalObject, prototype, TypeInfo(NumberObjectType, StructureFlags), info());
     }
+
+    static String toStringName(const JSObject*, JSGlobalObject*);
 };
 static_assert(sizeof(NumberObject) == sizeof(JSWrapperObject));
 
index c61a5ac..5f8bca8 100644 (file)
@@ -325,29 +325,29 @@ EncodedJSValue JSC_HOST_CALL objectProtoFuncToString(JSGlobalObject* globalObjec
     if (result)
         return JSValue::encode(result);
 
-    PropertyName toStringTagSymbol = vm.propertyNames->toStringTagSymbol;
-    RELEASE_AND_RETURN(scope, JSValue::encode(thisObject->getPropertySlot(globalObject, toStringTagSymbol, [&] (bool found, PropertySlot& toStringTagSlot) -> JSValue {
-        if (found) {
-            JSValue stringTag = toStringTagSlot.getValue(globalObject, toStringTagSymbol);
-            RETURN_IF_EXCEPTION(scope, { });
-            if (stringTag.isString()) {
-                JSString* result = jsString(globalObject, vm.smallStrings.objectStringStart(), asString(stringTag), vm.smallStrings.singleCharacterString(']'));
-                RETURN_IF_EXCEPTION(scope, { });
-                thisObject->structure(vm)->setObjectToStringValue(globalObject, vm, result, toStringTagSlot);
-                return result;
-            }
-        }
+    String tag = thisObject->methodTable(vm)->toStringName(thisObject, globalObject);
+    RETURN_IF_EXCEPTION(scope, { });
+    JSString* jsTag = nullptr;
 
-        String tag = thisObject->methodTable(vm)->toStringName(thisObject, globalObject);
+    PropertySlot slot(thisObject, PropertySlot::InternalMethodType::Get);
+    bool hasProperty = thisObject->getPropertySlot(globalObject, vm.propertyNames->toStringTagSymbol, slot);
+    EXCEPTION_ASSERT(!scope.exception() || !hasProperty);
+    if (hasProperty) {
+        JSValue tagValue = slot.getValue(globalObject, vm.propertyNames->toStringTagSymbol);
         RETURN_IF_EXCEPTION(scope, { });
-        String newString = tryMakeString("[object ", WTFMove(tag), "]");
-        if (!newString)
-            return throwOutOfMemoryError(globalObject, scope);
-
-        auto result = jsNontrivialString(vm, newString);
-        thisObject->structure(vm)->setObjectToStringValue(globalObject, vm, result, toStringTagSlot);
-        return result;
-    })));
+        if (tagValue.isString())
+            jsTag = asString(tagValue);
+    }
+
+    if (!jsTag) {
+        ASSERT_WITH_MESSAGE(tag.length() > 1, "toStringName() should return strings two or more characters long.");
+        jsTag = jsNontrivialString(vm, WTFMove(tag));
+    }
+
+    JSString* jsResult = jsString(globalObject, vm.smallStrings.objectStringStart(), jsTag, vm.smallStrings.singleCharacterString(']'));
+    RETURN_IF_EXCEPTION(scope, { });
+    thisObject->structure(vm)->setObjectToStringValue(globalObject, vm, jsResult, slot);
+    return JSValue::encode(jsResult);
 }
 
 } // namespace JSC
index 0e697bb..6803f2c 100644 (file)
@@ -51,24 +51,6 @@ ProxyObject::ProxyObject(VM& vm, Structure* structure)
 {
 }
 
-String ProxyObject::toStringName(const JSObject* object, JSGlobalObject* globalObject)
-{
-    VM& vm = globalObject->vm();
-    auto scope = DECLARE_THROW_SCOPE(vm);
-    const ProxyObject* proxy = jsCast<const ProxyObject*>(object);
-    while (proxy) {
-        const JSObject* target = proxy->target();
-        bool targetIsArray = isArray(globalObject, target);
-        if (UNLIKELY(scope.exception()))
-            break;
-        if (targetIsArray)
-            RELEASE_AND_RETURN(scope, target->classInfo(vm)->methodTable.toStringName(target, globalObject));
-
-        proxy = jsDynamicCast<const ProxyObject*>(vm, target);
-    }
-    return "Object"_s;
-}
-
 Structure* ProxyObject::structureForTarget(JSGlobalObject* globalObject, JSValue target)
 {
     VM& vm = globalObject->vm();
index cc3772e..a778b57 100644 (file)
@@ -80,7 +80,6 @@ private:
     JS_EXPORT_PRIVATE void finishCreation(VM&, JSGlobalObject*, JSValue target, JSValue handler);
     JS_EXPORT_PRIVATE static Structure* structureForTarget(JSGlobalObject*, JSValue target);
 
-    static String toStringName(const JSObject*, JSGlobalObject*);
     static bool getOwnPropertySlot(JSObject*, JSGlobalObject*, PropertyName, PropertySlot&);
     static bool getOwnPropertySlotByIndex(JSObject*, JSGlobalObject*, unsigned propertyName, PropertySlot&);
     static CallData getCallData(JSCell*);
index 1ce1b4c..0ce7e26 100644 (file)
@@ -167,6 +167,11 @@ bool RegExpObject::put(JSCell* cell, JSGlobalObject* globalObject, PropertyName
     return Base::put(cell, globalObject, propertyName, value, slot);
 }
 
+String RegExpObject::toStringName(const JSObject*, JSGlobalObject*)
+{
+    return "RegExp"_s;
+}
+
 JSValue RegExpObject::exec(JSGlobalObject* globalObject, JSString* string)
 {
     return execInline(globalObject, string);
index 71bf98b..0a416a2 100644 (file)
@@ -104,6 +104,7 @@ public:
 
     static bool getOwnPropertySlot(JSObject*, JSGlobalObject*, PropertyName, PropertySlot&);
     static bool put(JSCell*, JSGlobalObject*, PropertyName, JSValue, PutPropertySlot&);
+    static String toStringName(const JSObject*, JSGlobalObject*);
 
     DECLARE_EXPORT_INFO;
 
index 486dd92..52c1269 100644 (file)
@@ -166,6 +166,11 @@ void StringObject::getOwnNonIndexPropertyNames(JSObject* object, JSGlobalObject*
     return JSObject::getOwnNonIndexPropertyNames(thisObject, globalObject, propertyNames, mode);
 }
 
+String StringObject::toStringName(const JSObject*, JSGlobalObject*)
+{
+    return "String"_s;
+}
+
 StringObject* constructString(VM& vm, JSGlobalObject* globalObject, JSValue string)
 {
     StringObject* object = StringObject::create(vm, globalObject->stringObjectStructure());
index 7298b13..1e306f8 100644 (file)
@@ -62,6 +62,7 @@ public:
     JS_EXPORT_PRIVATE static void getOwnPropertyNames(JSObject*, JSGlobalObject*, PropertyNameArray&, EnumerationMode);
     JS_EXPORT_PRIVATE static void getOwnNonIndexPropertyNames(JSObject*, JSGlobalObject*, PropertyNameArray&, EnumerationMode);
     JS_EXPORT_PRIVATE static bool defineOwnProperty(JSObject*, JSGlobalObject*, PropertyName, const PropertyDescriptor&, bool shouldThrow);
+    static String toStringName(const JSObject*, JSGlobalObject*);
 
     DECLARE_EXPORT_INFO;
 
index ac237ac..ce25c14 100644 (file)
@@ -47,11 +47,6 @@ void SymbolObject::finishCreation(VM& vm, Symbol* symbol)
     setInternalValue(vm, symbol);
 }
 
-String SymbolObject::toStringName(const JSObject*, JSGlobalObject*)
-{
-    return "Object"_s;
-}
-
 JSValue SymbolObject::defaultValue(const JSObject* object, JSGlobalObject*, PreferredPrimitiveType)
 {
     const SymbolObject* symbolObject = jsCast<const SymbolObject*>(object);
index 9772ab3..2dd82d7 100644 (file)
@@ -62,8 +62,6 @@ public:
 
     static JSValue defaultValue(const JSObject*, JSGlobalObject*, PreferredPrimitiveType);
 
-    static String toStringName(const JSObject*, JSGlobalObject*);
-
 private:
     JS_EXPORT_PRIVATE void finishCreation(VM&, Symbol*);
     JS_EXPORT_PRIVATE SymbolObject(VM&, Structure*);
index d53ab26..4af0c73 100644 (file)
@@ -114,6 +114,7 @@ void JSWebAssembly::finishCreation(VM& vm, JSGlobalObject* globalObject)
 {
     Base::finishCreation(vm);
     ASSERT(inherits(vm, info()));
+    JSC_TO_STRING_TAG_WITHOUT_TRANSITION();
     if (Options::useWebAssemblyStreamingApi()) {
         JSC_BUILTIN_FUNCTION_WITHOUT_TRANSITION("compileStreaming", webAssemblyCompileStreamingCodeGenerator, static_cast<unsigned>(PropertyAttribute::DontEnum));
         JSC_BUILTIN_FUNCTION_WITHOUT_TRANSITION("instantiateStreaming", webAssemblyInstantiateStreamingCodeGenerator, static_cast<unsigned>(PropertyAttribute::DontEnum));
index e79d56b..b21925d 100644 (file)
@@ -1,3 +1,31 @@
+2020-05-05  Alexey Shvayka  <shvaikalesh@gmail.com>
+
+        Object.prototype.toString is not spec-perfect
+        https://bugs.webkit.org/show_bug.cgi?id=199138
+
+        Reviewed by Darin Adler and Keith Miller.
+
+        This patch defines @@toStringTag symbols for all WebIDL prototypes, including
+        interfaces that are not exposed, as required by the spec [1].
+
+        With updated JSObject::toStringName() and @@toStringTag symbols added in r260992,
+        className() and toStringName() methods of JSDOMConstructorBase can be safely removed.
+
+        [1]: https://heycam.github.io/webidl/#dfn-class-string
+
+        Tests: imported/w3c/web-platform-tests/WebIDL/ecmascript-binding/class-string-interface.any.js
+               imported/w3c/web-platform-tests/WebIDL/ecmascript-binding/class-string-iterator-prototype-object.any.js
+
+        * bindings/js/JSDOMConstructorBase.cpp:
+        (WebCore::JSDOMConstructorBase::className): Deleted.
+        (WebCore::JSDOMConstructorBase::toStringName): Deleted.
+        * bindings/js/JSDOMConstructorBase.h:
+        * bindings/scripts/CodeGeneratorJS.pm:
+        (GenerateImplementation):
+        (GeneratePrototypeDeclaration):
+        * bindings/scripts/test/JS/JSTestGlobalObject.cpp:
+        (WebCore::JSTestGlobalObjectPrototype::finishCreation):
+
 2020-05-04  Darin Adler  <darin@apple.com>
 
         [Mac] Remove __MAC_OS_X_VERSION_MIN_REQUIRED checks for versions older than 10.14
index 1d94b5d..30f5971 100644 (file)
@@ -46,19 +46,6 @@ CallData JSDOMConstructorBase::getCallData(JSCell*)
     return callData;
 }
 
-String JSDOMConstructorBase::className(const JSObject*, JSC::VM&)
-{
-    return "Function"_s;
-}
-
-String JSDOMConstructorBase::toStringName(const JSObject* object, JSC::JSGlobalObject* lexicalGlobalObject)
-{
-    VM& vm = lexicalGlobalObject->vm();
-    const ClassInfo* info = object->classInfo(vm);
-    ASSERT(info);
-    return info->methodTable.className(object, vm);
-}
-
 JSC::IsoSubspace* JSDOMConstructorBase::subspaceForImpl(JSC::VM& vm)
 {
     return &static_cast<JSVMClientData*>(vm.clientData)->domConstructorSpace();
index 2e0c5ac..00eb0be 100644 (file)
@@ -49,8 +49,6 @@ protected:
     {
     }
 
-    static String className(const JSObject*, JSC::VM&);
-    static String toStringName(const JSObject*, JSC::JSGlobalObject*);
     static JSC::CallData getCallData(JSC::JSCell*);
 };
 
index 2165c13..51a64ea 100644 (file)
@@ -4301,11 +4301,12 @@ sub GenerateImplementation
     my $hashTable = $justGenerateValueArray ? "nullptr" : "&${className}PrototypeTable";
     push(@implContent, "const ClassInfo ${className}Prototype::s_info = { \"${visibleInterfaceName}\", &Base::s_info, ${hashTable}, nullptr, CREATE_METHOD_TABLE(${className}Prototype) };\n\n");
 
-    if (PrototypeHasStaticPropertyTable($interface) || IsGlobalInterface($interface)) {
-        push(@implContent, "void ${className}Prototype::finishCreation(VM& vm)\n");
-        push(@implContent, "{\n");
-        push(@implContent, "    Base::finishCreation(vm);\n");
-        push(@implContent, "    reifyStaticProperties(vm, ${className}::info(), ${className}PrototypeTableValues, *this);\n") if !IsGlobalInterface($interface);
+    push(@implContent, "void ${className}Prototype::finishCreation(VM& vm)\n");
+    push(@implContent, "{\n");
+    push(@implContent, "    Base::finishCreation(vm);\n");
+
+    if (PrototypeHasStaticPropertyTable($interface) && !IsGlobalInterface($interface)) {
+        push(@implContent, "    reifyStaticProperties(vm, ${className}::info(), ${className}PrototypeTableValues, *this);\n");
 
         my @runtimeEnabledProperties = @runtimeEnabledOperations;
         push(@runtimeEnabledProperties, @runtimeEnabledAttributes);
@@ -4374,12 +4375,12 @@ sub GenerateImplementation
         push(@implContent, "    addValueIterableMethods(*globalObject(), *this);\n") if $interface->iterable and !IsKeyValueIterableInterface($interface);
 
         addUnscopableProperties($interface);
-
-        assert("JSC_TO_STRING_TAG_WITHOUT_TRANSITION() requires strings two or more characters long") if length($visibleInterfaceName) < 2;
-        push(@implContent, "    JSC_TO_STRING_TAG_WITHOUT_TRANSITION();\n");
-        push(@implContent, "}\n\n");
     }
 
+    assert("JSC_TO_STRING_TAG_WITHOUT_TRANSITION() requires strings two or more characters long") if length($visibleInterfaceName) < 2;
+    push(@implContent, "    JSC_TO_STRING_TAG_WITHOUT_TRANSITION();\n");
+    push(@implContent, "}\n\n");
+
     # - Initialize static ClassInfo object
     push(@implContent, "const ClassInfo $className" . "::s_info = { \"${visibleInterfaceName}\", &Base::s_info, ");
 
@@ -7339,12 +7340,8 @@ sub GeneratePrototypeDeclaration
     push(@$outputArray, "    {\n");
     push(@$outputArray, "    }\n");
 
-    if (PrototypeHasStaticPropertyTable($interface) || IsGlobalInterface($interface)) {
-        $structureFlags{"JSC::HasStaticPropertyTable"} = 1 if IsGlobalInterface($interface);
-
-        push(@$outputArray, "\n");
-        push(@$outputArray, "    void finishCreation(JSC::VM&);\n");
-    }
+    push(@$outputArray, "\n");
+    push(@$outputArray, "    void finishCreation(JSC::VM&);\n");
 
     # FIXME: Should this override putByIndex as well?
     if ($interface->extendedAttributes->{CustomPutOnPrototype}) {
@@ -7357,6 +7354,7 @@ sub GeneratePrototypeDeclaration
         push(@$outputArray, "    static bool defineOwnProperty(JSC::JSObject*, JSC::JSGlobalObject*, JSC::PropertyName, const JSC::PropertyDescriptor&, bool shouldThrow);\n");
     }
 
+    $structureFlags{"JSC::HasStaticPropertyTable"} = 1 if PrototypeHasStaticPropertyTable($interface) && IsGlobalInterface($interface);
     $structureFlags{"JSC::IsImmutablePrototypeExoticObject"} = 1 if $interface->extendedAttributes->{IsImmutablePrototypeExoticObjectOnPrototype};
 
     # structure flags
index 4e24b7a..acd69a0 100644 (file)
@@ -700,9 +700,6 @@ const ClassInfo JSTestGlobalObjectPrototype::s_info = { "TestGlobalObject", &Bas
 void JSTestGlobalObjectPrototype::finishCreation(VM& vm)
 {
     Base::finishCreation(vm);
-#if ENABLE(TEST_FEATURE)
-    putDirect(vm, static_cast<JSVMClientData*>(vm.clientData)->builtinNames().testPrivateFunctionPrivateName(), JSFunction::create(vm, globalObject(), 0, String(), jsTestGlobalObjectInstanceFunctionTestPrivateFunction), JSC::PropertyAttribute::ReadOnly | JSC::PropertyAttribute::DontEnum);
-#endif
     JSC_TO_STRING_TAG_WITHOUT_TRANSITION();
 }
 
index 6d9e3be..f9ffc8a 100644 (file)
@@ -1,3 +1,12 @@
+2020-05-05  Alexey Shvayka  <shvaikalesh@gmail.com>
+
+        Object.prototype.toString is not spec-perfect
+        https://bugs.webkit.org/show_bug.cgi?id=199138
+
+        Reviewed by Darin Adler and Keith Miller.
+
+        * TestWebKitAPI/Tests/JavaScriptCore/glib/TestJSC.cpp:
+
 2020-05-05  Tim Horton  <timothy_horton@apple.com>
 
         Excessive error logging from daemons trying to use WebKit, under -[UIDevice currentDevice]
index 4539010..5e18fee 100644 (file)
@@ -671,7 +671,7 @@ static void testJSCEvaluateInObject()
         g_assert_true(JSC_IS_VALUE(module.get()));
         g_assert_true(jsc_value_is_object(module.get()));
         GUniquePtr<char> valueString(jsc_value_to_string(module.get()));
-        g_assert_cmpstr(valueString.get(), ==, "[object GlobalObject]");
+        g_assert_cmpstr(valueString.get(), ==, "[object Object]");
         jsc_context_set_value(context.get(), "module", module.get());
 
         GRefPtr<JSCValue> bar = adoptGRef(jsc_value_object_get_property(module.get(), "bar"));