[ES6] Add support for toStringTag
authorkeith_miller@apple.com <keith_miller@apple.com@268f45cc-cd09-0410-ab3c-d52691b4dbfc>
Fri, 30 Oct 2015 21:37:25 +0000 (21:37 +0000)
committerkeith_miller@apple.com <keith_miller@apple.com@268f45cc-cd09-0410-ab3c-d52691b4dbfc>
Fri, 30 Oct 2015 21:37:25 +0000 (21:37 +0000)
https://bugs.webkit.org/show_bug.cgi?id=150696

Reviewed by Geoffrey Garen.

Source/JavaScriptCore:

This patch adds support for Symbol.toStringTag. This is a simple
feature, if an object passed to Object.prototype.toString() has a
toStringTag we use the tag in the string rather than the class info.
Added a test that checks this works for all the default supported classes
along with the corresponding prototype and custom cases.

* runtime/ArrayIteratorPrototype.cpp:
(JSC::ArrayIteratorPrototype::finishCreation):
* runtime/CommonIdentifiers.h:
* runtime/JSArrayBufferPrototype.cpp:
(JSC::JSArrayBufferPrototype::finishCreation):
* runtime/JSDataViewPrototype.cpp:
(JSC::JSDataViewPrototype::finishCreation):
* runtime/JSDataViewPrototype.h:
* runtime/JSModuleNamespaceObject.cpp:
(JSC::JSModuleNamespaceObject::finishCreation):
* runtime/JSONObject.cpp:
(JSC::JSONObject::finishCreation):
* runtime/JSPromisePrototype.cpp:
(JSC::JSPromisePrototype::finishCreation):
* runtime/JSTypedArrayViewPrototype.cpp:
(JSC::typedArrayViewProtoGetterFuncToStringTag):
(JSC::JSTypedArrayViewPrototype::finishCreation):
* runtime/MapIteratorPrototype.cpp:
(JSC::MapIteratorPrototype::finishCreation):
* runtime/MapPrototype.cpp:
(JSC::MapPrototype::finishCreation):
* runtime/MathObject.cpp:
(JSC::MathObject::finishCreation):
* runtime/ObjectPrototype.cpp:
(JSC::objectProtoFuncToString):
* runtime/SetIteratorPrototype.cpp:
(JSC::SetIteratorPrototype::finishCreation):
* runtime/SetPrototype.cpp:
(JSC::SetPrototype::finishCreation):
* runtime/SmallStrings.cpp:
(JSC::SmallStrings::SmallStrings):
(JSC::SmallStrings::initializeCommonStrings):
(JSC::SmallStrings::visitStrongReferences):
* runtime/SmallStrings.h:
(JSC::SmallStrings::objectStringStart):
* runtime/StringIteratorPrototype.cpp:
(JSC::StringIteratorPrototype::finishCreation):
* runtime/SymbolPrototype.cpp:
(JSC::SymbolPrototype::finishCreation):
* runtime/WeakMapPrototype.cpp:
(JSC::WeakMapPrototype::finishCreation):
* runtime/WeakSetPrototype.cpp:
(JSC::WeakSetPrototype::finishCreation):
* tests/modules/namespace.js:
* tests/stress/symbol-tostringtag.js: Added.
(toStr):
(strName):
(classes.string_appeared_here):

LayoutTests:

Symbol now has toStringTag as a member. Since Object.prototype.toString()
now does a [[Get]] on the object being stringed there are new console
error messages when accessing another window's properties.

* http/tests/history/cross-origin-replace-history-object-child-expected.txt:
* http/tests/security/cross-frame-access-custom-expected.txt:
* http/tests/security/cross-frame-access-history-get-expected.txt:
* http/tests/security/cross-frame-access-object-setPrototypeOf-expected.txt:
* js/Object-getOwnPropertyNames-expected.txt:
* js/script-tests/Object-getOwnPropertyNames.js:

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

31 files changed:
LayoutTests/ChangeLog
LayoutTests/http/tests/history/cross-origin-replace-history-object-child-expected.txt
LayoutTests/http/tests/security/cross-frame-access-custom-expected.txt
LayoutTests/http/tests/security/cross-frame-access-history-get-expected.txt
LayoutTests/http/tests/security/cross-frame-access-object-setPrototypeOf-expected.txt
LayoutTests/js/Object-getOwnPropertyNames-expected.txt
LayoutTests/js/script-tests/Object-getOwnPropertyNames.js
Source/JavaScriptCore/ChangeLog
Source/JavaScriptCore/runtime/ArrayIteratorPrototype.cpp
Source/JavaScriptCore/runtime/CommonIdentifiers.h
Source/JavaScriptCore/runtime/JSArrayBufferPrototype.cpp
Source/JavaScriptCore/runtime/JSDataViewPrototype.cpp
Source/JavaScriptCore/runtime/JSDataViewPrototype.h
Source/JavaScriptCore/runtime/JSModuleNamespaceObject.cpp
Source/JavaScriptCore/runtime/JSONObject.cpp
Source/JavaScriptCore/runtime/JSPromisePrototype.cpp
Source/JavaScriptCore/runtime/JSTypedArrayViewPrototype.cpp
Source/JavaScriptCore/runtime/MapIteratorPrototype.cpp
Source/JavaScriptCore/runtime/MapPrototype.cpp
Source/JavaScriptCore/runtime/MathObject.cpp
Source/JavaScriptCore/runtime/ObjectPrototype.cpp
Source/JavaScriptCore/runtime/SetIteratorPrototype.cpp
Source/JavaScriptCore/runtime/SetPrototype.cpp
Source/JavaScriptCore/runtime/SmallStrings.cpp
Source/JavaScriptCore/runtime/SmallStrings.h
Source/JavaScriptCore/runtime/StringIteratorPrototype.cpp
Source/JavaScriptCore/runtime/SymbolPrototype.cpp
Source/JavaScriptCore/runtime/WeakMapPrototype.cpp
Source/JavaScriptCore/runtime/WeakSetPrototype.cpp
Source/JavaScriptCore/tests/modules/namespace.js
Source/JavaScriptCore/tests/stress/symbol-tostringtag.js [new file with mode: 0644]

index 20563a6be15809cd2ea9db661bcfdb9b6322fb43..a06ac3c026806d5cfce8d566f3ba07a86f983c73 100644 (file)
@@ -1,3 +1,21 @@
+2015-10-30  Keith Miller  <keith_miller@apple.com>
+
+        [ES6] Add support for toStringTag
+        https://bugs.webkit.org/show_bug.cgi?id=150696
+
+        Reviewed by Geoffrey Garen.
+
+        Symbol now has toStringTag as a member. Since Object.prototype.toString()
+        now does a [[Get]] on the object being stringed there are new console
+        error messages when accessing another window's properties.
+
+        * http/tests/history/cross-origin-replace-history-object-child-expected.txt:
+        * http/tests/security/cross-frame-access-custom-expected.txt:
+        * http/tests/security/cross-frame-access-history-get-expected.txt:
+        * http/tests/security/cross-frame-access-object-setPrototypeOf-expected.txt:
+        * js/Object-getOwnPropertyNames-expected.txt:
+        * js/script-tests/Object-getOwnPropertyNames.js:
+
 2015-10-30  Ryan Haddad  <ryanhaddad@apple.com>
 
         http/tests/notifications/legacy/events.html flakily asserts on mac-wk2, updating expectations
index e925d6569d7b3f3e9927143b8aaedfc9d23d8864..9f2d8d56ed36ad99d86c4dbea468c713c2b3b7b8 100644 (file)
@@ -1,7 +1,9 @@
 CONSOLE MESSAGE: line 30: Blocked a frame with origin "http://127.0.0.1:8000" from accessing a frame with origin "http://localhost:8000". Protocols, domains, and ports must match.
+CONSOLE MESSAGE: line 24: Blocked a frame with origin "http://127.0.0.1:8000" from accessing a frame with origin "http://localhost:8000". Protocols, domains, and ports must match.
 ALERT: Child window's history object before attempt to clear: [object History]
 ALERT: About to shadow child window's history object: [object History]
 ALERT: Shadowed child window's history object: 
 CONSOLE MESSAGE: line 18: Blocked a frame with origin "http://127.0.0.1:8000" from accessing a frame with origin "http://localhost:8000". Protocols, domains, and ports must match.
+CONSOLE MESSAGE: line 18: Blocked a frame with origin "http://127.0.0.1:8000" from accessing a frame with origin "http://localhost:8000". Protocols, domains, and ports must match.
 ALERT: Child window's history object after attempt to clear: [object History]
 
index 49349da42db151c6716897ebf35bc4f37817cd30..63889a7c9d67f68bb82043bd11ee18f00109f06b 100644 (file)
@@ -16,6 +16,7 @@ CONSOLE MESSAGE: line 55: Blocked a frame with origin "http://127.0.0.1:8000" fr
 CONSOLE MESSAGE: line 81: Blocked a frame with origin "http://127.0.0.1:8000" from accessing a frame with origin "http://localhost:8000". Protocols, domains, and ports must match.
 CONSOLE MESSAGE: line 82: Blocked a frame with origin "http://127.0.0.1:8000" from accessing a frame with origin "http://localhost:8000". Protocols, domains, and ports must match.
 CONSOLE MESSAGE: line 81: Blocked a frame with origin "http://127.0.0.1:8000" from accessing a frame with origin "http://localhost:8000". Protocols, domains, and ports must match.
+CONSOLE MESSAGE: line 107: Blocked a frame with origin "http://127.0.0.1:8000" from accessing a frame with origin "http://localhost:8000". Protocols, domains, and ports must match.
 
 
 ----- tests for getting/setting interesting properties -----
index 5df413aa2f285693b8aa01c1ee344040e9e20e79..5dcb605f91b2488b3603f7583ce4f409f7fa6c10 100644 (file)
@@ -1,4 +1,5 @@
 CONSOLE MESSAGE: line 55: Blocked a frame with origin "http://127.0.0.1:8000" from accessing a frame with origin "http://localhost:8000". Protocols, domains, and ports must match.
+CONSOLE MESSAGE: line 107: Blocked a frame with origin "http://127.0.0.1:8000" from accessing a frame with origin "http://localhost:8000". Protocols, domains, and ports must match.
 CONSOLE MESSAGE: line 55: Blocked a frame with origin "http://127.0.0.1:8000" from accessing a frame with origin "http://localhost:8000". Protocols, domains, and ports must match.
 CONSOLE MESSAGE: line 55: Blocked a frame with origin "http://127.0.0.1:8000" from accessing a frame with origin "http://localhost:8000". Protocols, domains, and ports must match.
 CONSOLE MESSAGE: line 55: Blocked a frame with origin "http://127.0.0.1:8000" from accessing a frame with origin "http://localhost:8000". Protocols, domains, and ports must match.
index d08544cecaf95515774971a76ac9eebe9b8f5c37..6b425817ef039e0daa8889a658dfa0263485af6e 100644 (file)
@@ -1,7 +1,9 @@
 CONSOLE MESSAGE: line 1: Blocked a frame with origin "http://127.0.0.1:8000" from accessing a frame with origin "http://localhost:8000". Protocols, domains, and ports must match.
 CONSOLE MESSAGE: line 23: Blocked a frame with origin "http://127.0.0.1:8000" from accessing a frame with origin "http://localhost:8000". Protocols, domains, and ports must match.
+CONSOLE MESSAGE: line 25: Blocked a frame with origin "http://127.0.0.1:8000" from accessing a frame with origin "http://localhost:8000". Protocols, domains, and ports must match.
 CONSOLE MESSAGE: line 1: Blocked a frame with origin "http://127.0.0.1:8000" from accessing a frame with origin "http://localhost:8000". Protocols, domains, and ports must match.
 CONSOLE MESSAGE: line 24: Blocked a frame with origin "http://127.0.0.1:8000" from accessing a frame with origin "http://localhost:8000". Protocols, domains, and ports must match.
+CONSOLE MESSAGE: line 25: Blocked a frame with origin "http://127.0.0.1:8000" from accessing a frame with origin "http://localhost:8000". Protocols, domains, and ports must match.
 This tests that you can't set the prototype of the window or history objects cross-origin using Object.setPrototypeOf().
 
 PASS: targetWindow instanceof Array should be 'false' and is.
index 7e78bc87334e0b281e1ea18dd735f9dc194ff80c..cae219baf92b5950be77f9457da02cc51967f983 100644 (file)
@@ -61,7 +61,7 @@ PASS getSortedOwnPropertyNames(Error) is ['length', 'name', 'prototype']
 PASS getSortedOwnPropertyNames(Error.prototype) is ['constructor', 'message', 'name', 'toString']
 PASS getSortedOwnPropertyNames(Math) is ['E','LN10','LN2','LOG10E','LOG2E','PI','SQRT1_2','SQRT2','abs','acos','acosh','asin','asinh','atan','atan2','atanh','cbrt','ceil','clz32','cos','cosh','exp','expm1','floor','fround','hypot','imul','log','log10','log1p','log2','max','min','pow','random','round','sign','sin','sinh','sqrt','tan','tanh','trunc']
 PASS getSortedOwnPropertyNames(JSON) is ['parse', 'stringify']
-PASS getSortedOwnPropertyNames(Symbol) is ['for', 'iterator', 'keyFor', 'length', 'name', 'prototype', 'unscopables']
+PASS getSortedOwnPropertyNames(Symbol) is ['for', 'iterator', 'keyFor', 'length', 'name', 'prototype', 'toStringTag', 'unscopables']
 PASS getSortedOwnPropertyNames(Symbol.prototype) is ['constructor', 'toString', 'valueOf']
 PASS globalPropertyNames.indexOf('NaN') != -1 is true
 PASS globalPropertyNames.indexOf('Infinity') != -1 is true
index 0d56424882dca09d51077ce54a3a2a289952ed21..cb5ec24faf907f80237985f8c8ace838dd68e089 100644 (file)
@@ -70,7 +70,7 @@ var expectedPropertyNamesSet = {
     "Error.prototype": "['constructor', 'message', 'name', 'toString']",
     "Math": "['E','LN10','LN2','LOG10E','LOG2E','PI','SQRT1_2','SQRT2','abs','acos','acosh','asin','asinh','atan','atan2','atanh','cbrt','ceil','clz32','cos','cosh','exp','expm1','floor','fround','hypot','imul','log','log10','log1p','log2','max','min','pow','random','round','sign','sin','sinh','sqrt','tan','tanh','trunc']",
     "JSON": "['parse', 'stringify']",
-    "Symbol": "['for', 'iterator', 'keyFor', 'length', 'name', 'prototype', 'unscopables']",
+    "Symbol": "['for', 'iterator', 'keyFor', 'length', 'name', 'prototype', 'toStringTag', 'unscopables']",
     "Symbol.prototype": "['constructor', 'toString', 'valueOf']"
 };
 
index fa5f629331c2aa844057b38d0d8b03de81d0c5d9..8c999ca653892f27d9e89815c879bff7c8d4543c 100644 (file)
@@ -1,3 +1,65 @@
+2015-10-30  Keith Miller  <keith_miller@apple.com>
+
+        [ES6] Add support for toStringTag
+        https://bugs.webkit.org/show_bug.cgi?id=150696
+
+        Reviewed by Geoffrey Garen.
+
+        This patch adds support for Symbol.toStringTag. This is a simple
+        feature, if an object passed to Object.prototype.toString() has a
+        toStringTag we use the tag in the string rather than the class info.
+        Added a test that checks this works for all the default supported classes
+        along with the corresponding prototype and custom cases.
+
+        * runtime/ArrayIteratorPrototype.cpp:
+        (JSC::ArrayIteratorPrototype::finishCreation):
+        * runtime/CommonIdentifiers.h:
+        * runtime/JSArrayBufferPrototype.cpp:
+        (JSC::JSArrayBufferPrototype::finishCreation):
+        * runtime/JSDataViewPrototype.cpp:
+        (JSC::JSDataViewPrototype::finishCreation):
+        * runtime/JSDataViewPrototype.h:
+        * runtime/JSModuleNamespaceObject.cpp:
+        (JSC::JSModuleNamespaceObject::finishCreation):
+        * runtime/JSONObject.cpp:
+        (JSC::JSONObject::finishCreation):
+        * runtime/JSPromisePrototype.cpp:
+        (JSC::JSPromisePrototype::finishCreation):
+        * runtime/JSTypedArrayViewPrototype.cpp:
+        (JSC::typedArrayViewProtoGetterFuncToStringTag):
+        (JSC::JSTypedArrayViewPrototype::finishCreation):
+        * runtime/MapIteratorPrototype.cpp:
+        (JSC::MapIteratorPrototype::finishCreation):
+        * runtime/MapPrototype.cpp:
+        (JSC::MapPrototype::finishCreation):
+        * runtime/MathObject.cpp:
+        (JSC::MathObject::finishCreation):
+        * runtime/ObjectPrototype.cpp:
+        (JSC::objectProtoFuncToString):
+        * runtime/SetIteratorPrototype.cpp:
+        (JSC::SetIteratorPrototype::finishCreation):
+        * runtime/SetPrototype.cpp:
+        (JSC::SetPrototype::finishCreation):
+        * runtime/SmallStrings.cpp:
+        (JSC::SmallStrings::SmallStrings):
+        (JSC::SmallStrings::initializeCommonStrings):
+        (JSC::SmallStrings::visitStrongReferences):
+        * runtime/SmallStrings.h:
+        (JSC::SmallStrings::objectStringStart):
+        * runtime/StringIteratorPrototype.cpp:
+        (JSC::StringIteratorPrototype::finishCreation):
+        * runtime/SymbolPrototype.cpp:
+        (JSC::SymbolPrototype::finishCreation):
+        * runtime/WeakMapPrototype.cpp:
+        (JSC::WeakMapPrototype::finishCreation):
+        * runtime/WeakSetPrototype.cpp:
+        (JSC::WeakSetPrototype::finishCreation):
+        * tests/modules/namespace.js:
+        * tests/stress/symbol-tostringtag.js: Added.
+        (toStr):
+        (strName):
+        (classes.string_appeared_here):
+
 2015-10-29  Joseph Pecoraro  <pecoraro@apple.com>
 
         Web Inspector: Do not show JavaScriptCore builtins in inspector
index c330912597dc07746fc5d7c4eda57e96f7ac0520..d22223ac51e9967677552b04ccb948a1a4994ea4 100644 (file)
@@ -56,6 +56,7 @@ void ArrayIteratorPrototype::finishCreation(VM& vm, JSGlobalObject*)
 {
     Base::finishCreation(vm);
     ASSERT(inherits(info()));
+    putDirectWithoutTransition(vm, vm.propertyNames->toStringTagSymbol, jsString(&vm, "Array Iterator"), DontEnum | ReadOnly);
     vm.prototypeMap.addPrototype(this);
 }
 
index 110d8502ee14c1f97eafd9dac0b9440df2c45fc0..9572bc1f4bdf2ad62745a24702511a64c79f905d 100644 (file)
     macro(search) \
     macro(species) \
     macro(split) \
-    macro(toPrimitive) \
-    macro(toStringTag)
+    macro(toPrimitive)
 
 #define JSC_COMMON_PRIVATE_IDENTIFIERS_EACH_WELL_KNOWN_SYMBOL(macro) \
     macro(iterator) \
-    macro(unscopables)
+    macro(unscopables) \
+    macro(toStringTag)
 
 #define JSC_COMMON_BYTECODE_INTRINSICS_EACH_NAME(macro) \
     macro(putByValDirect) \
index ef650f6eb4b4f8c73c9595da7ab49093e87fca2c..adf2b6a752d6ef27b80bdf325b0b829852147096 100644 (file)
@@ -83,6 +83,7 @@ void JSArrayBufferPrototype::finishCreation(VM& vm, JSGlobalObject* globalObject
     Base::finishCreation(vm);
     
     JSC_NATIVE_FUNCTION(vm.propertyNames->slice, arrayBufferProtoFuncSlice, DontEnum, 2);
+    putDirectWithoutTransition(vm, vm.propertyNames->toStringTagSymbol, jsString(&vm, "ArrayBuffer"), DontEnum | ReadOnly);
 }
 
 JSArrayBufferPrototype* JSArrayBufferPrototype::create(VM& vm, JSGlobalObject* globalObject, Structure* structure)
index dd5b44e5b38f61c79beb920eb914410acedf80b4..90fe24e80ab1b7ae39aec6f6d6961184f8be1a08 100644 (file)
@@ -99,6 +99,12 @@ JSDataViewPrototype* JSDataViewPrototype::create(VM& vm, Structure* structure)
     return prototype;
 }
 
+void JSDataViewPrototype::finishCreation(JSC::VM& vm)
+{
+    Base::finishCreation(vm);
+    putDirectWithoutTransition(vm, vm.propertyNames->toStringTagSymbol, jsString(&vm, "DataView"), DontEnum | ReadOnly);
+}
+
 Structure* JSDataViewPrototype::createStructure(
     VM& vm, JSGlobalObject* globalObject, JSValue prototype)
 {
index bc72455ccc62c8ec55a346c0d8d40e71675d5945..46a6d2209c32073f476e8de714e16215a3cd27ee 100644 (file)
@@ -38,6 +38,8 @@ public:
 protected:
     JSDataViewPrototype(VM&, Structure*);
 
+    void finishCreation(VM&);
+
 public:
     static JSDataViewPrototype* create(VM&, Structure*);
     
index cb836a1e024df1eb1f1254f8e7a34e2982b8aac2..692feabb8db92c4cfc9258de5bef5e8c3cbf94a1 100644 (file)
@@ -72,6 +72,7 @@ void JSModuleNamespaceObject::finishCreation(VM& vm, JSGlobalObject* globalObjec
 
     m_moduleRecord.set(vm, this, moduleRecord);
     JSC_NATIVE_FUNCTION(vm.propertyNames->iteratorSymbol, moduleNamespaceObjectSymbolIterator, DontEnum, 0);
+    putDirect(vm, vm.propertyNames->toStringTagSymbol, jsString(&vm, "Module"), DontEnum | ReadOnly);
 
     // http://www.ecma-international.org/ecma-262/6.0/#sec-module-namespace-exotic-objects-getprototypeof
     // http://www.ecma-international.org/ecma-262/6.0/#sec-module-namespace-exotic-objects-setprototypeof-v
index 4a47f1876ee7d317e9d2a9dbe7ddfea27ae0b899..c8bda5cabd1d81110a8e47b4d05d4077e50af07c 100644 (file)
@@ -63,6 +63,8 @@ void JSONObject::finishCreation(VM& vm)
 {
     Base::finishCreation(vm);
     ASSERT(inherits(info()));
+
+    putDirectWithoutTransition(vm, vm.propertyNames->toStringTagSymbol, jsString(&vm, "JSON"), DontEnum | ReadOnly);
 }
 
 // PropertyNameForFunctionCall objects must be on the stack, since the JSValue that they create is not marked.
index 1d32335f3d055e040707cd51785716bcda95eab4..1bc5a1169f8524124b80b07fefccb442ca4da450 100644 (file)
@@ -74,6 +74,7 @@ JSPromisePrototype::JSPromisePrototype(VM& vm, Structure* structure)
 void JSPromisePrototype::finishCreation(VM& vm, Structure*)
 {
     Base::finishCreation(vm);
+    putDirectWithoutTransition(vm, vm.propertyNames->toStringTagSymbol, jsString(&vm, "Promise"), DontEnum | ReadOnly);
 }
 
 bool JSPromisePrototype::getOwnPropertySlot(JSObject* object, ExecState* exec, PropertyName propertyName, PropertySlot& slot)
index 53dd03bbb4e73e70fde1bae8376d92ccfb7c7b76..d47011bc1279c108d2d4a0888bf808ba02f0fdaa 100644 (file)
@@ -200,6 +200,40 @@ static EncodedJSValue JSC_HOST_CALL typedArrayViewProtoFuncValues(ExecState* exe
     CALL_GENERIC_TYPEDARRAY_PROTOTYPE_FUNCTION(typedArrayViewProtoFuncValues);
 }
 
+static EncodedJSValue JSC_HOST_CALL typedArrayViewProtoGetterFuncToStringTag(ExecState* exec)
+{
+    JSValue thisValue = exec->thisValue();
+    if (!thisValue.isObject())
+        return throwVMError(exec, createTypeError(exec, "Receiver should be a typed array view but was not an object"));
+
+    VM& vm = exec->vm();
+    switch (thisValue.getObject()->classInfo()->typedArrayStorageType) {
+    case TypeUint8Clamped:
+        return JSValue::encode(jsString(&vm, "Uint8ClampedArray"));
+    case TypeInt32:
+        return JSValue::encode(jsString(&vm, "Int32Array"));
+    case TypeUint32:
+        return JSValue::encode(jsString(&vm, "Uint32Array"));
+    case TypeFloat64:
+        return JSValue::encode(jsString(&vm, "Float64Array"));
+    case TypeFloat32:
+        return JSValue::encode(jsString(&vm, "Float32Array"));
+    case TypeInt8:
+        return JSValue::encode(jsString(&vm, "Int8Array"));
+    case TypeUint8:
+        return JSValue::encode(jsString(&vm, "Uint8Array"));
+    case TypeInt16:
+        return JSValue::encode(jsString(&vm, "Int16Array"));
+    case TypeUint16:
+        return JSValue::encode(jsString(&vm, "Uint16Array"));
+    case NotTypedArray:
+    case TypeDataView:
+        return throwVMError(exec, createTypeError(exec, "Receiver should be a typed array view"));
+    }
+    RELEASE_ASSERT_NOT_REACHED();
+}
+
+
 #undef CALL_GENERIC_TYPEDARRAY_PROTOTYPE_FUNCTION
 
 JSTypedArrayViewPrototype::JSTypedArrayViewPrototype(VM& vm, Structure* structure)
@@ -239,6 +273,7 @@ void JSTypedArrayViewPrototype::finishCreation(VM& vm, JSGlobalObject* globalObj
     JSC_NATIVE_FUNCTION(vm.propertyNames->subarray, typedArrayViewProtoFuncSubarray, DontEnum, 2);
     JSC_BUILTIN_FUNCTION(vm.propertyNames->toLocaleString, typedArrayPrototypeToLocaleStringCodeGenerator, DontEnum);
     JSC_NATIVE_FUNCTION(vm.propertyNames->toString, arrayProtoFuncToString, DontEnum, 0);
+    JSC_NATIVE_GETTER(vm.propertyNames->toStringTagSymbol, typedArrayViewProtoGetterFuncToStringTag, DontEnum | ReadOnly);
 
     JSFunction* valuesFunction = JSFunction::create(vm, globalObject, 0, vm.propertyNames->values.string(), typedArrayViewProtoFuncValues);
 
index 5e7ec33f9d52bc7147ed062c494b6b008802865f..dd7ade6eec8d03177e061ac0b9c262cff910d7bb 100644 (file)
@@ -45,6 +45,7 @@ void MapIteratorPrototype::finishCreation(VM& vm, JSGlobalObject* globalObject)
     vm.prototypeMap.addPrototype(this);
 
     JSC_NATIVE_FUNCTION(vm.propertyNames->next, MapIteratorPrototypeFuncNext, DontEnum, 0);
+    putDirectWithoutTransition(vm, vm.propertyNames->toStringTagSymbol, jsString(&vm, "Map Iterator"), DontEnum | ReadOnly);
 }
 
 EncodedJSValue JSC_HOST_CALL MapIteratorPrototypeFuncNext(CallFrame* callFrame)
index e972f540efb2f1e6a48d12503f0318971f42df82..be790dd1b84687cabfb45db3cae971075564f010 100644 (file)
@@ -75,6 +75,7 @@ void MapPrototype::finishCreation(VM& vm, JSGlobalObject* globalObject)
     JSFunction* entries = JSFunction::create(vm, globalObject, 0, vm.propertyNames->entries.string(), mapProtoFuncEntries);
     putDirectWithoutTransition(vm, vm.propertyNames->entries, entries, DontEnum);
     putDirectWithoutTransition(vm, vm.propertyNames->iteratorSymbol, entries, DontEnum);
+    putDirectWithoutTransition(vm, vm.propertyNames->toStringTagSymbol, jsString(&vm, "Map"), DontEnum | ReadOnly);
 
     GetterSetter* accessor = GetterSetter::create(vm, globalObject);
     JSFunction* function = JSFunction::create(vm, globalObject, 0, vm.propertyNames->size.string(), mapProtoFuncSize);
index e879eccaf05624a7a6957692c93e9c87ccd662a4..1a3be23ede61b05e4f50f87032361797ebd1ebaf 100644 (file)
@@ -94,6 +94,7 @@ void MathObject::finishCreation(VM& vm, JSGlobalObject* globalObject)
     putDirectWithoutTransition(vm, Identifier::fromString(&vm, "PI"), jsNumber(piDouble), DontDelete | DontEnum | ReadOnly);
     putDirectWithoutTransition(vm, Identifier::fromString(&vm, "SQRT1_2"), jsNumber(sqrt(0.5)), DontDelete | DontEnum | ReadOnly);
     putDirectWithoutTransition(vm, Identifier::fromString(&vm, "SQRT2"), jsNumber(sqrt(2.0)), DontDelete | DontEnum | ReadOnly);
+    putDirectWithoutTransition(vm, vm.propertyNames->toStringTagSymbol, jsString(&vm, "Math"), DontEnum | ReadOnly);
 
     putDirectNativeFunctionWithoutTransition(vm, globalObject, Identifier::fromString(&vm, "abs"), 1, mathProtoFuncAbs, AbsIntrinsic, DontEnum);
     putDirectNativeFunctionWithoutTransition(vm, globalObject, Identifier::fromString(&vm, "acos"), 1, mathProtoFuncACos, NoIntrinsic, DontEnum);
index 7e09f14f0de2e1a46c477f4e2d83f5714fd6fdc1..ae5296a8da4650d07aac2164bdb04556bc6c42c5 100644 (file)
@@ -26,6 +26,7 @@
 #include "JSFunction.h"
 #include "JSString.h"
 #include "JSCInlines.h"
+#include "PropertySlot.h"
 #include "StructureRareDataInlines.h"
 
 namespace JSC {
@@ -243,6 +244,15 @@ EncodedJSValue JSC_HOST_CALL objectProtoFuncToString(ExecState* exec)
         return JSValue::encode(thisValue.isUndefined() ? vm.smallStrings.undefinedObjectString() : vm.smallStrings.nullObjectString());
     JSObject* thisObject = thisValue.toObject(exec);
 
+    JSValue stringTag = thisObject->get(exec, exec->propertyNames().toStringTagSymbol);
+    if (stringTag.isString()) {
+        JSRopeString::RopeBuilder ropeBuilder(vm);
+        ropeBuilder.append(vm.smallStrings.objectStringStart());
+        ropeBuilder.append(jsCast<JSString*>(stringTag));
+        ropeBuilder.append(vm.smallStrings.singleCharacterString(']'));
+        return JSValue::encode(ropeBuilder.release());
+    }
+
     JSString* result = thisObject->structure(vm)->objectToStringValue();
     if (!result) {
         String newString = WTF::tryMakeString("[object ", thisObject->methodTable(exec->vm())->className(thisObject), "]");
index ab8df44475d1023dace03faaee503d0814a87383..b5d8427c96315d761b33a226ad168f2d0639de70 100644 (file)
@@ -45,6 +45,7 @@ void SetIteratorPrototype::finishCreation(VM& vm, JSGlobalObject* globalObject)
     vm.prototypeMap.addPrototype(this);
 
     JSC_NATIVE_FUNCTION(vm.propertyNames->next, SetIteratorPrototypeFuncNext, DontEnum, 0);
+    putDirectWithoutTransition(vm, vm.propertyNames->toStringTagSymbol, jsString(&vm, "Set Iterator"), DontEnum | ReadOnly);
 }
 
 EncodedJSValue JSC_HOST_CALL SetIteratorPrototypeFuncNext(CallFrame* callFrame)
index e83e383258f99bb05bbe11e0c65de04b8e049e0a..ddeee37b6f428e073af1efb011369f4a279056a9 100644 (file)
@@ -69,6 +69,7 @@ void SetPrototype::finishCreation(VM& vm, JSGlobalObject* globalObject)
     putDirectWithoutTransition(vm, vm.propertyNames->values, values, DontEnum);
     putDirectWithoutTransition(vm, vm.propertyNames->keys, values, DontEnum);
     putDirectWithoutTransition(vm, vm.propertyNames->iteratorSymbol, values, DontEnum);
+    putDirectWithoutTransition(vm, vm.propertyNames->toStringTagSymbol, jsString(&vm, "Set"), DontEnum | ReadOnly);
 
     GetterSetter* accessor = GetterSetter::create(vm, globalObject);
     JSFunction* function = JSFunction::create(vm, globalObject, 0, vm.propertyNames->size.string(), setProtoFuncSize);
index 76316b7fe6e9dab755794408d36de2c8feea8ab1..947518607b88b677e8d1f5eebe3d17657b24a31d 100644 (file)
@@ -66,6 +66,7 @@ SmallStrings::SmallStrings()
 #define JSC_COMMON_STRINGS_ATTRIBUTE_INITIALIZE(name) , m_##name(0)
     JSC_COMMON_STRINGS_EACH_NAME(JSC_COMMON_STRINGS_ATTRIBUTE_INITIALIZE)
 #undef JSC_COMMON_STRINGS_ATTRIBUTE_INITIALIZE
+    , m_objectStringStart(nullptr)
     , m_nullObjectString(nullptr)
     , m_undefinedObjectString(nullptr)
     , m_needsToBeVisited(true)
@@ -84,6 +85,7 @@ void SmallStrings::initializeCommonStrings(VM& vm)
 #define JSC_COMMON_STRINGS_ATTRIBUTE_INITIALIZE(name) initialize(&vm, m_##name, #name);
     JSC_COMMON_STRINGS_EACH_NAME(JSC_COMMON_STRINGS_ATTRIBUTE_INITIALIZE)
 #undef JSC_COMMON_STRINGS_ATTRIBUTE_INITIALIZE
+    initialize(&vm, m_objectStringStart, "[object ");
     initialize(&vm, m_nullObjectString, "[object Null]");
     initialize(&vm, m_undefinedObjectString, "[object Undefined]");
 }
@@ -97,6 +99,7 @@ void SmallStrings::visitStrongReferences(SlotVisitor& visitor)
 #define JSC_COMMON_STRINGS_ATTRIBUTE_VISIT(name) visitor.appendUnbarrieredPointer(&m_##name);
     JSC_COMMON_STRINGS_EACH_NAME(JSC_COMMON_STRINGS_ATTRIBUTE_VISIT)
 #undef JSC_COMMON_STRINGS_ATTRIBUTE_VISIT
+    visitor.appendUnbarrieredPointer(&m_objectStringStart);
     visitor.appendUnbarrieredPointer(&m_nullObjectString);
     visitor.appendUnbarrieredPointer(&m_undefinedObjectString);
 }
index 74f6e28792dd034a8cb1236f595ac839b5ff29f0..b90394edb7e8349c644bd682bf0823c9048ce3a0 100644 (file)
@@ -109,6 +109,7 @@ public:
         return nullptr;
     }
 
+    JSString* objectStringStart() const { return m_objectStringStart; }
     JSString* nullObjectString() const { return m_nullObjectString; }
     JSString* undefinedObjectString() const { return m_undefinedObjectString; }
 
@@ -131,6 +132,7 @@ private:
 #define JSC_COMMON_STRINGS_ATTRIBUTE_DECLARATION(name) JSString* m_##name;
     JSC_COMMON_STRINGS_EACH_NAME(JSC_COMMON_STRINGS_ATTRIBUTE_DECLARATION)
 #undef JSC_COMMON_STRINGS_ATTRIBUTE_DECLARATION
+    JSString* m_objectStringStart;
     JSString* m_nullObjectString;
     JSString* m_undefinedObjectString;
     JSString* m_singleCharacterStrings[singleCharacterStringCount];
index b58d0ddfb1c40fac13b914bcd0e4b602d75213a8..34a65e9010985769ad44c302a3c67d7eaec99a99 100644 (file)
@@ -54,6 +54,7 @@ void StringIteratorPrototype::finishCreation(VM& vm, JSGlobalObject*)
 {
     Base::finishCreation(vm);
     ASSERT(inherits(info()));
+    putDirectWithoutTransition(vm, vm.propertyNames->toStringTagSymbol, jsString(&vm, "String Iterator"), DontEnum | ReadOnly);
     vm.prototypeMap.addPrototype(this);
 }
 
index 2f4ac4dd5625418b2c0c89cd2b24aa0988f0d8b3..c15725f078d37d6d38d69580eabd054ace5422e4 100644 (file)
@@ -29,6 +29,7 @@
 
 #include "Error.h"
 #include "JSCInlines.h"
+#include "JSString.h"
 
 namespace JSC {
 
@@ -58,6 +59,7 @@ SymbolPrototype::SymbolPrototype(VM& vm, Structure* structure)
 void SymbolPrototype::finishCreation(VM& vm)
 {
     Base::finishCreation(vm);
+    putDirectWithoutTransition(vm, vm.propertyNames->toStringTagSymbol, jsString(&vm, "Symbol"), DontEnum | ReadOnly);
     ASSERT(inherits(info()));
 }
 
index 71c4c405537a50498216440da99730ace055078c..1579c329c1b9616a584b3abef65c16fc49429891 100644 (file)
@@ -50,6 +50,8 @@ void WeakMapPrototype::finishCreation(VM& vm, JSGlobalObject* globalObject)
     JSC_NATIVE_FUNCTION(vm.propertyNames->get, protoFuncWeakMapGet, DontEnum, 1);
     JSC_NATIVE_FUNCTION(vm.propertyNames->has, protoFuncWeakMapHas, DontEnum, 1);
     JSC_NATIVE_FUNCTION(vm.propertyNames->set, protoFuncWeakMapSet, DontEnum, 2);
+
+    putDirectWithoutTransition(vm, vm.propertyNames->toStringTagSymbol, jsString(&vm, "WeakMap"), DontEnum | ReadOnly);
 }
 
 static WeakMapData* getWeakMapData(CallFrame* callFrame, JSValue value)
index b718af74ee91a335d1a9ccb4ecc4f2380760cdba..fed3d67acf09de9048710953fe4dc622ac7aa9a4 100644 (file)
@@ -48,6 +48,8 @@ void WeakSetPrototype::finishCreation(VM& vm, JSGlobalObject* globalObject)
     JSC_NATIVE_FUNCTION(vm.propertyNames->deleteKeyword, protoFuncWeakSetDelete, DontEnum, 1);
     JSC_NATIVE_FUNCTION(vm.propertyNames->has, protoFuncWeakSetHas, DontEnum, 1);
     JSC_NATIVE_FUNCTION(vm.propertyNames->add, protoFuncWeakSetAdd, DontEnum, 1);
+
+    putDirectWithoutTransition(vm, vm.propertyNames->toStringTagSymbol, jsString(&vm, "WeakSet"), DontEnum | ReadOnly);
 }
 
 static WeakMapData* getWeakMapData(CallFrame* callFrame, JSValue value)
index 1bf2414532a902feb0793e665c82bcf8179a43b0..678928269bcb35f762fcc1d2d14d63f04185dced 100644 (file)
@@ -55,8 +55,9 @@ shouldBe(Reflect.getPrototypeOf(namespace), null);
 
 // These names should be shown in the code point order.
 shouldBe(JSON.stringify(Object.getOwnPropertyNames(namespace)), `["Cappuccino","Cocoa","Matcha","Mocha","default"]`);
-shouldBe(Object.getOwnPropertySymbols(namespace).length, 1);
+shouldBe(Object.getOwnPropertySymbols(namespace).length, 2);
 shouldBe(Object.getOwnPropertySymbols(namespace)[0], Symbol.iterator);
+shouldBe(Object.getOwnPropertySymbols(namespace)[1], Symbol.toStringTag);
 
 shouldBe(typeof namespace[Symbol.iterator], 'function');
 var array = Array.from(namespace);
diff --git a/Source/JavaScriptCore/tests/stress/symbol-tostringtag.js b/Source/JavaScriptCore/tests/stress/symbol-tostringtag.js
new file mode 100644 (file)
index 0000000..642109c
--- /dev/null
@@ -0,0 +1,48 @@
+// This file tests the names of all the classes with builtin Symbol.toStringTags and Object.prototype.toString().
+
+foo = { };
+foo[Symbol.toStringTag] = "test the tag";
+
+if (foo != "[object test the tag]")
+    throw "failed on custom toStringTag";
+
+function toStr(obj) {
+    return Object.prototype.toString.call(obj);
+}
+
+function strName(str) { return "[object " + str + "]"; }
+
+if (toStr(Symbol()) !== strName("Symbol"))
+    throw "failed on Symbol";
+
+if (toStr(Symbol.prototype) !== strName("Symbol"))
+    throw "failed on Symbol.prototype";
+
+objects = ["JSON", "Math"];
+
+for (name of objects) {
+    value = eval(name)
+    if (toStr(value) !== strName(name))
+        throw "failed on " + name;
+}
+
+iterators = ['Array', 'Map', 'Set', 'String'];
+
+for (name of iterators) {
+    value = eval('new ' + name + '()[Symbol.iterator]()');
+    if (toStr(value) !== strName(name + ' Iterator'))
+        throw 'failed on Iterator of ' + name;
+    if (toStr(Object.getPrototypeOf(value)) !== strName(name + ' Iterator'))
+        throw 'failed on Iterator.prototype of ' + name;
+}
+
+classes = { "ArrayBuffer": 10, "DataView": new ArrayBuffer(10), "Promise": function() { return 1 }, "Set": undefined, "WeakMap": undefined, "WeakSet": undefined };
+
+for (name in classes) {
+    value = eval(name);
+    if (toStr(new value(classes[name])) !== strName(name))
+        throw "failed on new object of " + name;
+    if (toStr(value.prototype) !== strName(name))
+        throw "failed on prototype of " + name;
+}
+