Implement ES6 Object.getOwnPropertySymbols
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: http://svn.webkit.org/repository/webkit/trunk@182343 268f45cc-cd09-0410-ab3c-d52691b4dbfc
diff --git a/Source/JavaScriptCore/ChangeLog b/Source/JavaScriptCore/ChangeLog
index d8fd81d..dd07a24 100644
--- a/Source/JavaScriptCore/ChangeLog
+++ b/Source/JavaScriptCore/ChangeLog
@@ -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.
diff --git a/Source/JavaScriptCore/builtins/BuiltinExecutables.cpp b/Source/JavaScriptCore/builtins/BuiltinExecutables.cpp
index cb30608..0b9627b 100644
--- a/Source/JavaScriptCore/builtins/BuiltinExecutables.cpp
+++ b/Source/JavaScriptCore/builtins/BuiltinExecutables.cpp
@@ -101,7 +101,7 @@
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));
diff --git a/Source/JavaScriptCore/builtins/BuiltinNames.h b/Source/JavaScriptCore/builtins/BuiltinNames.h
index 7b4783a..79acc14 100644
--- a/Source/JavaScriptCore/builtins/BuiltinNames.h
+++ b/Source/JavaScriptCore/builtins/BuiltinNames.h
@@ -64,6 +64,8 @@
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 @@
#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());
diff --git a/Source/JavaScriptCore/runtime/CommonIdentifiers.cpp b/Source/JavaScriptCore/runtime/CommonIdentifiers.cpp
index 0b28d5c..a6d191e 100644
--- a/Source/JavaScriptCore/runtime/CommonIdentifiers.cpp
+++ b/Source/JavaScriptCore/runtime/CommonIdentifiers.cpp
@@ -51,6 +51,16 @@
{
}
+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);
diff --git a/Source/JavaScriptCore/runtime/CommonIdentifiers.h b/Source/JavaScriptCore/runtime/CommonIdentifiers.h
index 39bde55..2dd582a 100644
--- a/Source/JavaScriptCore/runtime/CommonIdentifiers.h
+++ b/Source/JavaScriptCore/runtime/CommonIdentifiers.h
@@ -302,6 +302,9 @@
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;
};
diff --git a/Source/JavaScriptCore/runtime/EnumerationMode.h b/Source/JavaScriptCore/runtime/EnumerationMode.h
index c0cf380..3e95ed3 100644
--- a/Source/JavaScriptCore/runtime/EnumerationMode.h
+++ b/Source/JavaScriptCore/runtime/EnumerationMode.h
@@ -33,6 +33,11 @@
Exclude
};
+enum class SymbolPropertiesMode {
+ Include,
+ Exclude
+};
+
enum class JSObjectPropertiesMode {
Include,
Exclude
@@ -40,14 +45,16 @@
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 @@
return m_dontEnumPropertiesMode == DontEnumPropertiesMode::Include;
}
+ bool includeSymbolProperties()
+ {
+ return m_symbolPropertiesMode == SymbolPropertiesMode::Include;
+ }
+
bool includeJSObjectProperties()
{
return m_jsObjectPropertiesMode == JSObjectPropertiesMode::Include;
@@ -66,6 +78,7 @@
private:
DontEnumPropertiesMode m_dontEnumPropertiesMode;
+ SymbolPropertiesMode m_symbolPropertiesMode;
JSObjectPropertiesMode m_jsObjectPropertiesMode;
};
diff --git a/Source/JavaScriptCore/runtime/ExceptionHelpers.cpp b/Source/JavaScriptCore/runtime/ExceptionHelpers.cpp
index 10fa930..3f02c2f 100644
--- a/Source/JavaScriptCore/runtime/ExceptionHelpers.cpp
+++ b/Source/JavaScriptCore/runtime/ExceptionHelpers.cpp
@@ -82,7 +82,7 @@
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);
}
diff --git a/Source/JavaScriptCore/runtime/JSGlobalObject.cpp b/Source/JavaScriptCore/runtime/JSGlobalObject.cpp
index d39618a..1d4aed0 100644
--- a/Source/JavaScriptCore/runtime/JSGlobalObject.cpp
+++ b/Source/JavaScriptCore/runtime/JSGlobalObject.cpp
@@ -325,7 +325,7 @@
// 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());
diff --git a/Source/JavaScriptCore/runtime/JSLexicalEnvironment.cpp b/Source/JavaScriptCore/runtime/JSLexicalEnvironment.cpp
index e79c29c..ea9947f 100644
--- a/Source/JavaScriptCore/runtime/JSLexicalEnvironment.cpp
+++ b/Source/JavaScriptCore/runtime/JSLexicalEnvironment.cpp
@@ -112,7 +112,7 @@
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()));
}
diff --git a/Source/JavaScriptCore/runtime/JSSymbolTableObject.cpp b/Source/JavaScriptCore/runtime/JSSymbolTableObject.cpp
index 14115d9..c08ff59 100644
--- a/Source/JavaScriptCore/runtime/JSSymbolTableObject.cpp
+++ b/Source/JavaScriptCore/runtime/JSSymbolTableObject.cpp
@@ -61,10 +61,11 @@
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()));
+ }
}
}
diff --git a/Source/JavaScriptCore/runtime/ObjectConstructor.cpp b/Source/JavaScriptCore/runtime/ObjectConstructor.cpp
index a13761d..f68aa03 100644
--- a/Source/JavaScriptCore/runtime/ObjectConstructor.cpp
+++ b/Source/JavaScriptCore/runtime/ObjectConstructor.cpp
@@ -34,12 +34,14 @@
#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 @@
{
}
-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 @@
}
// 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 @@
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 @@
}
}
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 @@
// 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 @@
// 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 @@
// 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 @@
// 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 @@
// 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.
diff --git a/Source/JavaScriptCore/runtime/ObjectConstructor.h b/Source/JavaScriptCore/runtime/ObjectConstructor.h
index 1252781..bb067b1 100644
--- a/Source/JavaScriptCore/runtime/ObjectConstructor.h
+++ b/Source/JavaScriptCore/runtime/ObjectConstructor.h
@@ -33,10 +33,10 @@
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 @@
}
protected:
- void finishCreation(VM&, ObjectPrototype*);
+ void finishCreation(VM&, JSGlobalObject*, ObjectPrototype*);
static const unsigned StructureFlags = OverridesGetOwnPropertySlot | InternalFunction::StructureFlags;
private:
diff --git a/Source/JavaScriptCore/runtime/Structure.cpp b/Source/JavaScriptCore/runtime/Structure.cpp
index 4cb0177..563a5b5 100644
--- a/Source/JavaScriptCore/runtime/Structure.cpp
+++ b/Source/JavaScriptCore/runtime/Structure.cpp
@@ -939,7 +939,9 @@
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
index 0000000..031c3fa4
--- /dev/null
+++ b/Source/JavaScriptCore/tests/stress/object-get-own-property-symbols-perform-to-object.js
@@ -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
index 0000000..40e93d8
--- /dev/null
+++ b/Source/JavaScriptCore/tests/stress/object-get-own-property-symbols.js
@@ -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
index 0000000..bac3ec0
--- /dev/null
+++ b/Source/JavaScriptCore/tests/stress/symbol-define-property.js
@@ -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
index 0000000..4f507cd
--- /dev/null
+++ b/Source/JavaScriptCore/tests/stress/symbol-seal-and-freeze.js
@@ -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
index 0000000..3c03d5d
--- /dev/null
+++ b/Source/JavaScriptCore/tests/stress/symbol-with-json.js
@@ -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') ]);