Implement ES6 Object.getOwnPropertySymbols
authorutatane.tea@gmail.com <utatane.tea@gmail.com@268f45cc-cd09-0410-ab3c-d52691b4dbfc>
Sat, 4 Apr 2015 14:32:53 +0000 (14:32 +0000)
committerutatane.tea@gmail.com <utatane.tea@gmail.com@268f45cc-cd09-0410-ab3c-d52691b4dbfc>
Sat, 4 Apr 2015 14:32:53 +0000 (14:32 +0000)
https://bugs.webkit.org/show_bug.cgi?id=141106

Reviewed by Geoffrey Garen.

Source/JavaScriptCore:

This patch implements `Object.getOwnPropertySymbols`.
One technical issue is that, since we use private symbols (such as `@Object`) in the
privileged JS code in `builtins/`, they should not be exposed.
To distinguish them from the usual symbols, check the target `StringImpl*` is a not private name
before adding it into PropertyNameArray.

To check the target `StringImpl*` is a private name, we leverage privateToPublic map in `BuiltinNames`
since all private symbols are held in this map.

* builtins/BuiltinExecutables.cpp:
(JSC::BuiltinExecutables::createExecutableInternal):
* builtins/BuiltinNames.h:
(JSC::BuiltinNames::isPrivateName):
* runtime/CommonIdentifiers.cpp:
(JSC::CommonIdentifiers::isPrivateName):
* runtime/CommonIdentifiers.h:
* runtime/EnumerationMode.h:
(JSC::EnumerationMode::EnumerationMode):
(JSC::EnumerationMode::includeSymbolProperties):
* runtime/ExceptionHelpers.cpp:
(JSC::createUndefinedVariableError):
* runtime/JSGlobalObject.cpp:
(JSC::JSGlobalObject::init):
* runtime/JSLexicalEnvironment.cpp:
(JSC::JSLexicalEnvironment::getOwnNonIndexPropertyNames):
* runtime/JSSymbolTableObject.cpp:
(JSC::JSSymbolTableObject::getOwnNonIndexPropertyNames):
* runtime/ObjectConstructor.cpp:
(JSC::ObjectConstructor::finishCreation):
(JSC::objectConstructorGetOwnPropertySymbols):
(JSC::defineProperties):
(JSC::objectConstructorSeal):
(JSC::objectConstructorFreeze):
(JSC::objectConstructorIsSealed):
(JSC::objectConstructorIsFrozen):
* runtime/ObjectConstructor.h:
(JSC::ObjectConstructor::create):
* runtime/Structure.cpp:
(JSC::Structure::getPropertyNamesFromStructure):
* tests/stress/object-get-own-property-symbols-perform-to-object.js: Added.
(compare):
* tests/stress/object-get-own-property-symbols.js: Added.
(forIn):
* tests/stress/symbol-define-property.js: Added.
(testSymbol):
* tests/stress/symbol-seal-and-freeze.js: Added.
* tests/stress/symbol-with-json.js: Added.

LayoutTests:

* js/Object-getOwnPropertyNames-expected.txt:
* js/script-tests/Object-getOwnPropertyNames.js:

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

21 files changed:
LayoutTests/ChangeLog
LayoutTests/js/Object-getOwnPropertyNames-expected.txt
LayoutTests/js/script-tests/Object-getOwnPropertyNames.js
Source/JavaScriptCore/ChangeLog
Source/JavaScriptCore/builtins/BuiltinExecutables.cpp
Source/JavaScriptCore/builtins/BuiltinNames.h
Source/JavaScriptCore/runtime/CommonIdentifiers.cpp
Source/JavaScriptCore/runtime/CommonIdentifiers.h
Source/JavaScriptCore/runtime/EnumerationMode.h
Source/JavaScriptCore/runtime/ExceptionHelpers.cpp
Source/JavaScriptCore/runtime/JSGlobalObject.cpp
Source/JavaScriptCore/runtime/JSLexicalEnvironment.cpp
Source/JavaScriptCore/runtime/JSSymbolTableObject.cpp
Source/JavaScriptCore/runtime/ObjectConstructor.cpp
Source/JavaScriptCore/runtime/ObjectConstructor.h
Source/JavaScriptCore/runtime/Structure.cpp
Source/JavaScriptCore/tests/stress/object-get-own-property-symbols-perform-to-object.js [new file with mode: 0644]
Source/JavaScriptCore/tests/stress/object-get-own-property-symbols.js [new file with mode: 0644]
Source/JavaScriptCore/tests/stress/symbol-define-property.js [new file with mode: 0644]
Source/JavaScriptCore/tests/stress/symbol-seal-and-freeze.js [new file with mode: 0644]
Source/JavaScriptCore/tests/stress/symbol-with-json.js [new file with mode: 0644]

index 414c77a..cab5043 100644 (file)
@@ -1,3 +1,13 @@
+2015-04-04  Yusuke Suzuki  <utatane.tea@gmail.com>
+
+        Implement ES6 Object.getOwnPropertySymbols
+        https://bugs.webkit.org/show_bug.cgi?id=141106
+
+        Reviewed by Geoffrey Garen.
+
+        * js/Object-getOwnPropertyNames-expected.txt:
+        * js/script-tests/Object-getOwnPropertyNames.js:
+
 2015-04-03  Tim Horton  <timothy_horton@apple.com>
 
         fast/fixed-layout/fixed-layout.html is flaky
index b6285e1..f126d9b 100644 (file)
@@ -40,7 +40,7 @@ PASS getSortedOwnPropertyNames(decodeURI) is ['length', 'name']
 PASS getSortedOwnPropertyNames(decodeURIComponent) is ['length', 'name']
 PASS getSortedOwnPropertyNames(encodeURI) is ['length', 'name']
 PASS getSortedOwnPropertyNames(encodeURIComponent) is ['length', 'name']
-PASS getSortedOwnPropertyNames(Object) is ['create', 'defineProperties', 'defineProperty', 'freeze', 'getOwnPropertyDescriptor', 'getOwnPropertyNames', 'getPrototypeOf', 'isExtensible', 'isFrozen', 'isSealed', 'keys', 'length', 'name', 'preventExtensions', 'prototype', 'seal']
+PASS getSortedOwnPropertyNames(Object) is ['create', 'defineProperties', 'defineProperty', 'freeze', 'getOwnPropertyDescriptor', 'getOwnPropertyNames', 'getOwnPropertySymbols', 'getPrototypeOf', 'isExtensible', 'isFrozen', 'isSealed', 'keys', 'length', 'name', 'preventExtensions', 'prototype', 'seal']
 PASS getSortedOwnPropertyNames(Object.prototype) is ['__defineGetter__', '__defineSetter__', '__lookupGetter__', '__lookupSetter__', '__proto__', 'constructor', 'hasOwnProperty', 'isPrototypeOf', 'propertyIsEnumerable', 'toLocaleString', 'toString', 'valueOf']
 PASS getSortedOwnPropertyNames(Function) is ['length', 'name', 'prototype']
 PASS getSortedOwnPropertyNames(Function.prototype) is ['apply', 'bind', 'call', 'constructor', 'length', 'name', 'toString']
index b0a272f..91bbb8f 100644 (file)
@@ -48,7 +48,7 @@ var expectedPropertyNamesSet = {
     "encodeURI": "['length', 'name']",
     "encodeURIComponent": "['length', 'name']",
 // Built-in ECMA objects
-    "Object": "['create', 'defineProperties', 'defineProperty', 'freeze', 'getOwnPropertyDescriptor', 'getOwnPropertyNames', 'getPrototypeOf', 'isExtensible', 'isFrozen', 'isSealed', 'keys', 'length', 'name', 'preventExtensions', 'prototype', 'seal']",
+    "Object": "['create', 'defineProperties', 'defineProperty', 'freeze', 'getOwnPropertyDescriptor', 'getOwnPropertyNames', 'getOwnPropertySymbols', 'getPrototypeOf', 'isExtensible', 'isFrozen', 'isSealed', 'keys', 'length', 'name', 'preventExtensions', 'prototype', 'seal']",
     "Object.prototype": "['__defineGetter__', '__defineSetter__', '__lookupGetter__', '__lookupSetter__', '__proto__', 'constructor', 'hasOwnProperty', 'isPrototypeOf', 'propertyIsEnumerable', 'toLocaleString', 'toString', 'valueOf']",
     "Function": "['length', 'name', 'prototype']",
     "Function.prototype": "['apply', 'bind', 'call', 'constructor', 'length', 'name', 'toString']",
index d8fd81d..dd07a24 100644 (file)
@@ -1,3 +1,58 @@
+2015-04-04  Yusuke Suzuki  <utatane.tea@gmail.com>
+
+        Implement ES6 Object.getOwnPropertySymbols
+        https://bugs.webkit.org/show_bug.cgi?id=141106
+
+        Reviewed by Geoffrey Garen.
+
+        This patch implements `Object.getOwnPropertySymbols`.
+        One technical issue is that, since we use private symbols (such as `@Object`) in the
+        privileged JS code in `builtins/`, they should not be exposed.
+        To distinguish them from the usual symbols, check the target `StringImpl*` is a not private name
+        before adding it into PropertyNameArray.
+
+        To check the target `StringImpl*` is a private name, we leverage privateToPublic map in `BuiltinNames`
+        since all private symbols are held in this map.
+
+        * builtins/BuiltinExecutables.cpp:
+        (JSC::BuiltinExecutables::createExecutableInternal):
+        * builtins/BuiltinNames.h:
+        (JSC::BuiltinNames::isPrivateName):
+        * runtime/CommonIdentifiers.cpp:
+        (JSC::CommonIdentifiers::isPrivateName):
+        * runtime/CommonIdentifiers.h:
+        * runtime/EnumerationMode.h:
+        (JSC::EnumerationMode::EnumerationMode):
+        (JSC::EnumerationMode::includeSymbolProperties):
+        * runtime/ExceptionHelpers.cpp:
+        (JSC::createUndefinedVariableError):
+        * runtime/JSGlobalObject.cpp:
+        (JSC::JSGlobalObject::init):
+        * runtime/JSLexicalEnvironment.cpp:
+        (JSC::JSLexicalEnvironment::getOwnNonIndexPropertyNames):
+        * runtime/JSSymbolTableObject.cpp:
+        (JSC::JSSymbolTableObject::getOwnNonIndexPropertyNames):
+        * runtime/ObjectConstructor.cpp:
+        (JSC::ObjectConstructor::finishCreation):
+        (JSC::objectConstructorGetOwnPropertySymbols):
+        (JSC::defineProperties):
+        (JSC::objectConstructorSeal):
+        (JSC::objectConstructorFreeze):
+        (JSC::objectConstructorIsSealed):
+        (JSC::objectConstructorIsFrozen):
+        * runtime/ObjectConstructor.h:
+        (JSC::ObjectConstructor::create):
+        * runtime/Structure.cpp:
+        (JSC::Structure::getPropertyNamesFromStructure):
+        * tests/stress/object-get-own-property-symbols-perform-to-object.js: Added.
+        (compare):
+        * tests/stress/object-get-own-property-symbols.js: Added.
+        (forIn):
+        * tests/stress/symbol-define-property.js: Added.
+        (testSymbol):
+        * tests/stress/symbol-seal-and-freeze.js: Added.
+        * tests/stress/symbol-with-json.js: Added.
+
 2015-04-03  Mark Lam  <mark.lam@apple.com>
 
         Add Options::jitPolicyScale() as a single knob to make all compilations happen sooner.
index cb30608..0b9627b 100644 (file)
@@ -101,7 +101,7 @@ UnlinkedFunctionExecutable* BuiltinExecutables::createExecutableInternal(const S
         
         if (closedVariable == m_vm.propertyNames->undefinedKeyword.impl())
             continue;
-        RELEASE_ASSERT(closedVariable->isSymbol());
+        RELEASE_ASSERT(m_vm.propertyNames->isPrivateName(closedVariable.get()));
     }
     body->overrideName(name);
     UnlinkedFunctionExecutable* functionExecutable = UnlinkedFunctionExecutable::create(&m_vm, source, body, kind, WTF::move(sourceOverride));
index 7b4783a..79acc14 100644 (file)
@@ -64,6 +64,8 @@ public:
         JSC_COMMON_PRIVATE_IDENTIFIERS_EACH_WELL_KNOWN_SYMBOL(INITIALISE_PUBLIC_TO_PRIVATE_ENTRY)
     }
 
+    bool isPrivateName(StringImpl* uid) const;
+    bool isPrivateName(const Identifier&) const;
     const Identifier* getPrivateName(const Identifier&) const;
     const Identifier& getPublicName(const Identifier&) const;
     
@@ -88,6 +90,18 @@ private:
 #undef INITIALISE_BUILTIN_SYMBOLS
 #undef DECLARE_BUILTIN_SYMBOL_ACCESSOR
 
+inline bool BuiltinNames::isPrivateName(StringImpl* uid) const
+{
+    if (!uid->isSymbol())
+        return false;
+    return m_privateToPublicMap.contains(uid);
+}
+
+inline bool BuiltinNames::isPrivateName(const Identifier& ident) const
+{
+    return isPrivateName(ident.impl());
+}
+
 inline const Identifier* BuiltinNames::getPrivateName(const Identifier& ident) const
 {
     auto iter = m_publicToPrivateMap.find(ident.impl());
index 0b28d5c..a6d191e 100644 (file)
@@ -51,6 +51,16 @@ CommonIdentifiers::~CommonIdentifiers()
 {
 }
 
+bool CommonIdentifiers::isPrivateName(StringImpl* uid) const
+{
+    return m_builtinNames->isPrivateName(uid);
+}
+
+bool CommonIdentifiers::isPrivateName(const Identifier& ident) const
+{
+    return m_builtinNames->isPrivateName(ident);
+}
+
 const Identifier* CommonIdentifiers::getPrivateName(const Identifier& ident) const
 {
     return m_builtinNames->getPrivateName(ident);
index 39bde55..2dd582a 100644 (file)
@@ -302,6 +302,9 @@ namespace JSC {
         JSC_COMMON_PRIVATE_IDENTIFIERS_EACH_WELL_KNOWN_SYMBOL(JSC_IDENTIFIER_DECLARE_PRIVATE_WELL_KNOWN_SYMBOL_GLOBAL)
 #undef JSC_IDENTIFIER_DECLARE_PRIVATE_WELL_KNOWN_SYMBOL_GLOBAL
 
+        bool isPrivateName(StringImpl* uid) const;
+        bool isPrivateName(const Identifier&) const;
+
         const Identifier* getPrivateName(const Identifier&) const;
         Identifier getPublicName(const Identifier&) const;
     };
index c0cf380..3e95ed3 100644 (file)
@@ -33,6 +33,11 @@ enum class DontEnumPropertiesMode {
     Exclude
 };
 
+enum class SymbolPropertiesMode {
+    Include,
+    Exclude
+};
+
 enum class JSObjectPropertiesMode {
     Include,
     Exclude
@@ -40,14 +45,16 @@ enum class JSObjectPropertiesMode {
 
 class EnumerationMode {
 public:
-    EnumerationMode(DontEnumPropertiesMode dontEnumPropertiesMode = DontEnumPropertiesMode::Exclude, JSObjectPropertiesMode jsObjectPropertiesMode = JSObjectPropertiesMode::Include)
+    EnumerationMode(DontEnumPropertiesMode dontEnumPropertiesMode = DontEnumPropertiesMode::Exclude, SymbolPropertiesMode symbolPropertiesMode = SymbolPropertiesMode::Exclude, JSObjectPropertiesMode jsObjectPropertiesMode = JSObjectPropertiesMode::Include)
         : m_dontEnumPropertiesMode(dontEnumPropertiesMode)
+        , m_symbolPropertiesMode(symbolPropertiesMode)
         , m_jsObjectPropertiesMode(jsObjectPropertiesMode)
     {
     }
 
     EnumerationMode(const EnumerationMode& mode, JSObjectPropertiesMode jsObjectPropertiesMode)
         : m_dontEnumPropertiesMode(mode.m_dontEnumPropertiesMode)
+        , m_symbolPropertiesMode(mode.m_symbolPropertiesMode)
         , m_jsObjectPropertiesMode(jsObjectPropertiesMode)
     {
     }
@@ -59,6 +66,11 @@ public:
         return m_dontEnumPropertiesMode == DontEnumPropertiesMode::Include;
     }
 
+    bool includeSymbolProperties()
+    {
+        return m_symbolPropertiesMode == SymbolPropertiesMode::Include;
+    }
+
     bool includeJSObjectProperties()
     {
         return m_jsObjectPropertiesMode == JSObjectPropertiesMode::Include;
@@ -66,6 +78,7 @@ public:
 
 private:
     DontEnumPropertiesMode m_dontEnumPropertiesMode;
+    SymbolPropertiesMode m_symbolPropertiesMode;
     JSObjectPropertiesMode m_jsObjectPropertiesMode;
 };
 
index 10fa930..3f02c2f 100644 (file)
@@ -82,7 +82,7 @@ JSObject* createStackOverflowError(JSGlobalObject* globalObject)
 
 JSObject* createUndefinedVariableError(ExecState* exec, const Identifier& ident)
 {
-    if (ident.impl()->isSymbol()) {
+    if (exec->propertyNames().isPrivateName(ident)) {
         String message(makeString("Can't find private variable: @", exec->propertyNames().getPublicName(ident).string()));
         return createReferenceError(exec, message);
     }
index d39618a..1d4aed0 100644 (file)
@@ -325,7 +325,7 @@ m_ ## properName ## Structure.set(vm, this, instanceType::createStructure(vm, th
     
     // Constructors
     
-    ObjectConstructor* objectConstructor = ObjectConstructor::create(vm, ObjectConstructor::createStructure(vm, this, m_functionPrototype.get()), m_objectPrototype.get());
+    ObjectConstructor* objectConstructor = ObjectConstructor::create(vm, this, ObjectConstructor::createStructure(vm, this, m_functionPrototype.get()), m_objectPrototype.get());
     m_objectConstructor.set(vm, this, objectConstructor);
     JSCell* functionConstructor = FunctionConstructor::create(vm, FunctionConstructor::createStructure(vm, this, m_functionPrototype.get()), m_functionPrototype.get());
     JSCell* arrayConstructor = ArrayConstructor::create(vm, ArrayConstructor::createStructure(vm, this, m_functionPrototype.get()), m_arrayPrototype.get());
index e79c29c..ea9947f 100644 (file)
@@ -112,7 +112,7 @@ void JSLexicalEnvironment::getOwnNonIndexPropertyNames(JSObject* object, ExecSta
                 continue;
             if (!thisObject->isValid(it->value.scopeOffset()))
                 continue;
-            if (it->key->isSymbol())
+            if (it->key->isSymbol() && !mode.includeSymbolProperties())
                 continue;
             propertyNames.add(Identifier::fromUid(exec, it->key.get()));
         }
index 14115d9..c08ff59 100644 (file)
@@ -61,10 +61,11 @@ void JSSymbolTableObject::getOwnNonIndexPropertyNames(JSObject* object, ExecStat
         ConcurrentJITLocker locker(thisObject->symbolTable()->m_lock);
         SymbolTable::Map::iterator end = thisObject->symbolTable()->end(locker);
         for (SymbolTable::Map::iterator it = thisObject->symbolTable()->begin(locker); it != end; ++it) {
-            if (it->key->isSymbol())
-                continue;
-            if (!(it->value.getAttributes() & DontEnum) || mode.includeDontEnumProperties())
+            if (!(it->value.getAttributes() & DontEnum) || mode.includeDontEnumProperties()) {
+                if (it->key->isSymbol() && !mode.includeSymbolProperties())
+                    continue;
                 propertyNames.add(Identifier::fromUid(exec, it->key.get()));
+            }
         }
     }
     
index a13761d..f68aa03 100644 (file)
 #include "PropertyDescriptor.h"
 #include "PropertyNameArray.h"
 #include "StackVisitor.h"
+#include "Symbol.h"
 
 namespace JSC {
 
 EncodedJSValue JSC_HOST_CALL objectConstructorGetPrototypeOf(ExecState*);
 EncodedJSValue JSC_HOST_CALL objectConstructorGetOwnPropertyDescriptor(ExecState*);
 EncodedJSValue JSC_HOST_CALL objectConstructorGetOwnPropertyNames(ExecState*);
+EncodedJSValue JSC_HOST_CALL objectConstructorGetOwnPropertySymbols(ExecState*);
 EncodedJSValue JSC_HOST_CALL objectConstructorKeys(ExecState*);
 EncodedJSValue JSC_HOST_CALL objectConstructorDefineProperty(ExecState*);
 EncodedJSValue JSC_HOST_CALL objectConstructorDefineProperties(ExecState*);
@@ -84,13 +86,16 @@ ObjectConstructor::ObjectConstructor(VM& vm, Structure* structure)
 {
 }
 
-void ObjectConstructor::finishCreation(VM& vm, ObjectPrototype* objectPrototype)
+void ObjectConstructor::finishCreation(VM& vm, JSGlobalObject* globalObject, ObjectPrototype* objectPrototype)
 {
     Base::finishCreation(vm, objectPrototype->classInfo()->className);
     // ECMA 15.2.3.1
     putDirectWithoutTransition(vm, vm.propertyNames->prototype, objectPrototype, DontEnum | DontDelete | ReadOnly);
     // no. of arguments for constructor
     putDirectWithoutTransition(vm, vm.propertyNames->length, jsNumber(1), ReadOnly | DontEnum | DontDelete);
+
+    if (globalObject->runtimeFlags().isSymbolEnabled())
+        JSC_NATIVE_FUNCTION("getOwnPropertySymbols", objectConstructorGetOwnPropertySymbols, DontEnum, 1);
 }
 
 bool ObjectConstructor::getOwnPropertySlot(JSObject* object, ExecState* exec, PropertyName propertyName, PropertySlot &slot)
@@ -216,6 +221,24 @@ EncodedJSValue JSC_HOST_CALL objectConstructorGetOwnPropertyNames(ExecState* exe
 }
 
 // FIXME: Use the enumeration cache.
+EncodedJSValue JSC_HOST_CALL objectConstructorGetOwnPropertySymbols(ExecState* exec)
+{
+    JSObject* object = exec->argument(0).toObject(exec);
+    if (exec->hadException())
+        return JSValue::encode(jsNull());
+    PropertyNameArray properties(exec);
+    object->methodTable(exec->vm())->getOwnPropertyNames(object, exec, properties, EnumerationMode(DontEnumPropertiesMode::Include, SymbolPropertiesMode::Include));
+    JSArray* names = constructEmptyArray(exec, 0);
+    size_t numProperties = properties.size();
+    for (size_t i = 0; i < numProperties; i++) {
+        AtomicStringImpl* impl = properties[i].impl();
+        if (impl->isSymbol() && !exec->propertyNames().isPrivateName(impl))
+            names->push(exec, Symbol::create(exec->vm(), impl));
+    }
+    return JSValue::encode(names);
+}
+
+// FIXME: Use the enumeration cache.
 EncodedJSValue JSC_HOST_CALL objectConstructorKeys(ExecState* exec)
 {
     JSObject* object = exec->argument(0).toObject(exec);
@@ -333,7 +356,7 @@ EncodedJSValue JSC_HOST_CALL objectConstructorDefineProperty(ExecState* exec)
 static JSValue defineProperties(ExecState* exec, JSObject* object, JSObject* properties)
 {
     PropertyNameArray propertyNames(exec);
-    asObject(properties)->methodTable(exec->vm())->getOwnPropertyNames(asObject(properties), exec, propertyNames, EnumerationMode());
+    asObject(properties)->methodTable(exec->vm())->getOwnPropertyNames(asObject(properties), exec, propertyNames, EnumerationMode(DontEnumPropertiesMode::Exclude, SymbolPropertiesMode::Include));
     size_t numProperties = propertyNames.size();
     Vector<PropertyDescriptor> descriptors;
     MarkedArgumentBuffer markBuffer;
@@ -356,7 +379,10 @@ static JSValue defineProperties(ExecState* exec, JSObject* object, JSObject* pro
         }
     }
     for (size_t i = 0; i < numProperties; i++) {
-        object->methodTable(exec->vm())->defineOwnProperty(object, exec, propertyNames[i], descriptors[i], true);
+        Identifier propertyName = propertyNames[i];
+        if (exec->propertyNames().isPrivateName(propertyName))
+            continue;
+        object->methodTable(exec->vm())->defineOwnProperty(object, exec, propertyName, descriptors[i], true);
         if (exec->hadException())
             return jsNull();
     }
@@ -400,17 +426,20 @@ EncodedJSValue JSC_HOST_CALL objectConstructorSeal(ExecState* exec)
 
     // 2. For each named own property name P of O,
     PropertyNameArray properties(exec);
-    object->methodTable(exec->vm())->getOwnPropertyNames(object, exec, properties, EnumerationMode(DontEnumPropertiesMode::Include));
+    object->methodTable(exec->vm())->getOwnPropertyNames(object, exec, properties, EnumerationMode(DontEnumPropertiesMode::Include, SymbolPropertiesMode::Include));
     PropertyNameArray::const_iterator end = properties.end();
     for (PropertyNameArray::const_iterator iter = properties.begin(); iter != end; ++iter) {
+        Identifier propertyName = *iter;
+        if (exec->propertyNames().isPrivateName(propertyName))
+            continue;
         // a. Let desc be the result of calling the [[GetOwnProperty]] internal method of O with P.
         PropertyDescriptor desc;
-        if (!object->getOwnPropertyDescriptor(exec, *iter, desc))
+        if (!object->getOwnPropertyDescriptor(exec, propertyName, desc))
             continue;
         // b. If desc.[[Configurable]] is true, set desc.[[Configurable]] to false.
         desc.setConfigurable(false);
         // c. Call the [[DefineOwnProperty]] internal method of O with P, desc, and true as arguments.
-        object->methodTable(exec->vm())->defineOwnProperty(object, exec, *iter, desc, true);
+        object->methodTable(exec->vm())->defineOwnProperty(object, exec, propertyName, desc, true);
         if (exec->hadException())
             return JSValue::encode(obj);
     }
@@ -437,12 +466,15 @@ EncodedJSValue JSC_HOST_CALL objectConstructorFreeze(ExecState* exec)
 
     // 2. For each named own property name P of O,
     PropertyNameArray properties(exec);
-    object->methodTable(exec->vm())->getOwnPropertyNames(object, exec, properties, EnumerationMode(DontEnumPropertiesMode::Include));
+    object->methodTable(exec->vm())->getOwnPropertyNames(object, exec, properties, EnumerationMode(DontEnumPropertiesMode::Include, SymbolPropertiesMode::Include));
     PropertyNameArray::const_iterator end = properties.end();
     for (PropertyNameArray::const_iterator iter = properties.begin(); iter != end; ++iter) {
+        Identifier propertyName = *iter;
+        if (exec->propertyNames().isPrivateName(propertyName))
+            continue;
         // a. Let desc be the result of calling the [[GetOwnProperty]] internal method of O with P.
         PropertyDescriptor desc;
-        if (!object->getOwnPropertyDescriptor(exec, *iter, desc))
+        if (!object->getOwnPropertyDescriptor(exec, propertyName, desc))
             continue;
         // b. If IsDataDescriptor(desc) is true, then
         // i. If desc.[[Writable]] is true, set desc.[[Writable]] to false.
@@ -451,7 +483,7 @@ EncodedJSValue JSC_HOST_CALL objectConstructorFreeze(ExecState* exec)
         // c. If desc.[[Configurable]] is true, set desc.[[Configurable]] to false.
         desc.setConfigurable(false);
         // d. Call the [[DefineOwnProperty]] internal method of O with P, desc, and true as arguments.
-        object->methodTable(exec->vm())->defineOwnProperty(object, exec, *iter, desc, true);
+        object->methodTable(exec->vm())->defineOwnProperty(object, exec, propertyName, desc, true);
         if (exec->hadException())
             return JSValue::encode(obj);
     }
@@ -485,12 +517,15 @@ EncodedJSValue JSC_HOST_CALL objectConstructorIsSealed(ExecState* exec)
 
     // 2. For each named own property name P of O,
     PropertyNameArray properties(exec);
-    object->methodTable(exec->vm())->getOwnPropertyNames(object, exec, properties, EnumerationMode(DontEnumPropertiesMode::Include));
+    object->methodTable(exec->vm())->getOwnPropertyNames(object, exec, properties, EnumerationMode(DontEnumPropertiesMode::Include, SymbolPropertiesMode::Include));
     PropertyNameArray::const_iterator end = properties.end();
     for (PropertyNameArray::const_iterator iter = properties.begin(); iter != end; ++iter) {
+        Identifier propertyName = *iter;
+        if (exec->propertyNames().isPrivateName(propertyName))
+            continue;
         // a. Let desc be the result of calling the [[GetOwnProperty]] internal method of O with P.
         PropertyDescriptor desc;
-        if (!object->getOwnPropertyDescriptor(exec, *iter, desc))
+        if (!object->getOwnPropertyDescriptor(exec, propertyName, desc))
             continue;
         // b. If desc.[[Configurable]] is true, then return false.
         if (desc.configurable())
@@ -515,12 +550,15 @@ EncodedJSValue JSC_HOST_CALL objectConstructorIsFrozen(ExecState* exec)
 
     // 2. For each named own property name P of O,
     PropertyNameArray properties(exec);
-    object->methodTable(exec->vm())->getOwnPropertyNames(object, exec, properties, EnumerationMode(DontEnumPropertiesMode::Include));
+    object->methodTable(exec->vm())->getOwnPropertyNames(object, exec, properties, EnumerationMode(DontEnumPropertiesMode::Include, SymbolPropertiesMode::Include));
     PropertyNameArray::const_iterator end = properties.end();
     for (PropertyNameArray::const_iterator iter = properties.begin(); iter != end; ++iter) {
+        Identifier propertyName = *iter;
+        if (exec->propertyNames().isPrivateName(propertyName))
+            continue;
         // a. Let desc be the result of calling the [[GetOwnProperty]] internal method of O with P.
         PropertyDescriptor desc;
-        if (!object->getOwnPropertyDescriptor(exec, *iter, desc))
+        if (!object->getOwnPropertyDescriptor(exec, propertyName, desc))
             continue;
         // b. If IsDataDescriptor(desc) is true then
         // i. If desc.[[Writable]] is true, return false. c. If desc.[[Configurable]] is true, then return false.
index 1252781..bb067b1 100644 (file)
@@ -33,10 +33,10 @@ class ObjectConstructor : public InternalFunction {
 public:
     typedef InternalFunction Base;
 
-    static ObjectConstructor* create(VM& vm, Structure* structure, ObjectPrototype* objectPrototype)
+    static ObjectConstructor* create(VM& vm, JSGlobalObject* globalObject, Structure* structure, ObjectPrototype* objectPrototype)
     {
         ObjectConstructor* constructor = new (NotNull, allocateCell<ObjectConstructor>(vm.heap)) ObjectConstructor(vm, structure);
-        constructor->finishCreation(vm, objectPrototype);
+        constructor->finishCreation(vm, globalObject, objectPrototype);
         return constructor;
     }
 
@@ -50,7 +50,7 @@ public:
     }
 
 protected:
-    void finishCreation(VM&, ObjectPrototype*);
+    void finishCreation(VM&, JSGlobalObject*, ObjectPrototype*);
     static const unsigned StructureFlags = OverridesGetOwnPropertySlot | InternalFunction::StructureFlags;
 
 private:
index 4cb0177..563a5b5 100644 (file)
@@ -939,7 +939,9 @@ void Structure::getPropertyNamesFromStructure(VM& vm, PropertyNameArray& propert
     PropertyTable::iterator end = propertyTable()->end();
     for (PropertyTable::iterator iter = propertyTable()->begin(); iter != end; ++iter) {
         ASSERT(hasNonEnumerableProperties() || !(iter->attributes & DontEnum));
-        if (!iter->key->isSymbol() && (!(iter->attributes & DontEnum) || mode.includeDontEnumProperties())) {
+        if (!(iter->attributes & DontEnum) || mode.includeDontEnumProperties()) {
+            if (iter->key->isSymbol() && !mode.includeSymbolProperties())
+                continue;
             if (knownUnique)
                 propertyNames.addKnownUnique(iter->key);
             else
diff --git a/Source/JavaScriptCore/tests/stress/object-get-own-property-symbols-perform-to-object.js b/Source/JavaScriptCore/tests/stress/object-get-own-property-symbols-perform-to-object.js
new file mode 100644 (file)
index 0000000..031c3fa
--- /dev/null
@@ -0,0 +1,39 @@
+var primitives = [
+    ["string", []],
+    [42, []],
+    [Symbol("symbol"), []],
+    [true, []],
+    [false, []]
+];
+
+function compare(ax, bx) {
+    if (ax.length !== bx.length)
+        return false;
+    for (var i = 0, iz = ax.length; i < iz; ++i) {
+        if (ax[i] !== bx[i])
+            return false;
+    }
+    return true;
+}
+
+for (var [primitive, expected] of primitives) {
+    var ret = Object.getOwnPropertySymbols(primitive);
+    if (!compare(ret, expected))
+        throw new Error("bad value for " + String(primitive) + ": " + String(ret));
+}
+
+[
+    [ null, "TypeError: null is not an object (evaluating 'Object.getOwnPropertySymbols(value)')" ],
+    [ undefined, "TypeError: undefined is not an object (evaluating 'Object.getOwnPropertySymbols(value)')" ]
+].forEach(function ([value, message]) {
+    var error = null;
+    try {
+        Object.getOwnPropertySymbols(value);
+    } catch (e) {
+        error = e;
+    }
+    if (!error)
+        throw new Error("error not thrown");
+    if (String(error) !== message)
+        throw new Error("bad error: " + String(error));
+});
diff --git a/Source/JavaScriptCore/tests/stress/object-get-own-property-symbols.js b/Source/JavaScriptCore/tests/stress/object-get-own-property-symbols.js
new file mode 100644 (file)
index 0000000..40e93d8
--- /dev/null
@@ -0,0 +1,35 @@
+// This tests Object.getOwnPropertySymbols.
+
+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 object = {};
+var symbol = Symbol("Cocoa");
+object[symbol] = "Cappuccino";
+if (Object.getOwnPropertyNames(object).length !== 0)
+    throw "Error: bad value " + Object.getOwnPropertyNames(object).length;
+if (Object.getOwnPropertySymbols(object).length !== 1)
+    throw "Error: bad value " + Object.getOwnPropertySymbols(object).length;
+if (Object.getOwnPropertySymbols(object)[0] !== symbol)
+    throw "Error: bad value " + String(Object.getOwnPropertySymbols(object)[0]);
+
+function forIn(obj) {
+    var array = [];
+    // Symbol should not be enumerated.
+    for (var key in obj) array.push(key);
+    return array;
+}
+
+if (forIn(object).length !== 0)
+    throw "Error: bad value " + forIn(object).length;
+if (Object.keys(object).length !== 0)
+    throw "Error: bad value " + Object.keys(object).length;
+
+delete object[symbol];
+if (Object.getOwnPropertyNames(object).length !== 0)
+    throw "Error: bad value " + Object.getOwnPropertyNames(object).length;
+if (Object.getOwnPropertySymbols(object).length !== 0)
+    throw "Error: bad value " + Object.getOwnPropertySymbols(object).length;
diff --git a/Source/JavaScriptCore/tests/stress/symbol-define-property.js b/Source/JavaScriptCore/tests/stress/symbol-define-property.js
new file mode 100644 (file)
index 0000000..bac3ec0
--- /dev/null
@@ -0,0 +1,33 @@
+// This tests Object.create, Object.defineProperty, Object.defineProperties work with Symbol.
+
+function testSymbol(object) {
+    if (!object.hasOwnProperty(Symbol.iterator))
+        throw "Error: object doesn't have Symbol.iterator";
+    if (object.propertyIsEnumerable(Symbol.iterator))
+        throw "Error: Symbol.iterator is defined as enumerable";
+    if (JSON.stringify(Object.getOwnPropertyDescriptor(object, Symbol.iterator)) !== '{"value":42,"writable":false,"enumerable":false,"configurable":false}')
+        throw "Error: bad property descriptor " + JSON.stringify(Object.getOwnPropertyDescriptor(object, Symbol.iterator));
+    if (Object.getOwnPropertySymbols(object).length !== 1)
+    throw "Error: bad value " + Object.getOwnPropertySymbols(object).length;
+    if (Object.getOwnPropertySymbols(object)[0] !== Symbol.iterator)
+        throw "Error: bad value " + String(Object.getOwnPropertySymbols(object)[0]);
+}
+
+var object = Object.create(Object.prototype, {
+    [Symbol.iterator]: {
+        value: 42
+    }
+});
+testSymbol(object);
+
+var object = Object.defineProperties({}, {
+    [Symbol.iterator]: {
+        value: 42
+    }
+});
+testSymbol(object);
+
+var object = Object.defineProperty({}, Symbol.iterator, {
+    value: 42
+});
+testSymbol(object);
diff --git a/Source/JavaScriptCore/tests/stress/symbol-seal-and-freeze.js b/Source/JavaScriptCore/tests/stress/symbol-seal-and-freeze.js
new file mode 100644 (file)
index 0000000..4f507cd
--- /dev/null
@@ -0,0 +1,26 @@
+// This tests Object.seal and Object.freeze affect on Symbol properties.
+
+var object = {
+    [Symbol.iterator]: 42
+};
+
+if (!object.hasOwnProperty(Symbol.iterator))
+    throw "Error: object doesn't have Symbol.iterator";
+if (JSON.stringify(Object.getOwnPropertyDescriptor(object, Symbol.iterator)) !== '{"value":42,"writable":true,"enumerable":true,"configurable":true}')
+    throw "Error: bad property descriptor " + JSON.stringify(Object.getOwnPropertyDescriptor(object, Symbol.iterator));
+if (Object.getOwnPropertySymbols(object).length !== 1)
+    throw "Error: bad value " + Object.getOwnPropertySymbols(object).length;
+if (Object.getOwnPropertySymbols(object)[0] !== Symbol.iterator)
+    throw "Error: bad value " + String(Object.getOwnPropertySymbols(object)[0]);
+
+Object.seal(object);
+if (!object.hasOwnProperty(Symbol.iterator))
+    throw "Error: object doesn't have Symbol.iterator";
+if (JSON.stringify(Object.getOwnPropertyDescriptor(object, Symbol.iterator)) !== '{"value":42,"writable":true,"enumerable":true,"configurable":false}')
+    throw "Error: bad property descriptor " + JSON.stringify(Object.getOwnPropertyDescriptor(object, Symbol.iterator));
+
+Object.freeze(object);
+if (!object.hasOwnProperty(Symbol.iterator))
+    throw "Error: object doesn't have Symbol.iterator";
+if (JSON.stringify(Object.getOwnPropertyDescriptor(object, Symbol.iterator)) !== '{"value":42,"writable":false,"enumerable":true,"configurable":false}')
+    throw "Error: bad property descriptor " + JSON.stringify(Object.getOwnPropertyDescriptor(object, Symbol.iterator));
diff --git a/Source/JavaScriptCore/tests/stress/symbol-with-json.js b/Source/JavaScriptCore/tests/stress/symbol-with-json.js
new file mode 100644 (file)
index 0000000..3c03d5d
--- /dev/null
@@ -0,0 +1,14 @@
+// This tests JSON correctly behaves with Symbol.
+
+if (JSON.stringify(Symbol('Cocoa')) !== undefined)
+    throw "Error: bad value " + JSON.stringify(Symbol('Cocoa'));
+
+var object = {};
+var symbol = Symbol("Cocoa");
+object[symbol] = 42;
+object['Cappuccino'] = 42;
+if (JSON.stringify(object) !== '{"Cappuccino":42}')
+    throw "Error: bad value " + JSON.stringify(object);
+
+if (JSON.stringify(object, [ Symbol('Cocoa') ]) !== "{}")
+    throw "Error: bad value " + JSON.stringify(object, [ Symbol('Cocoa') ]);