Commit d1f19755 authored by oliver@apple.com's avatar oliver@apple.com

[ES5] Implement Object.keys

https://bugs.webkit.org/show_bug.cgi?id=29170

Reviewed by Maciej Stachowiak.

This patch basically requires two separate steps, the first is to split getPropertyNames
into two functions -- getOwnPropertyNames and getPropertyNames, basically making them behave
in the same way as getOwnPropertySlot and getPropertySlot.  In essence getOwnPropertyNames
produces the list of properties on an object excluding its prototype chain and getPropertyNames
just iterates the the object and its prototype chain calling getOwnPropertyNames at each level.

git-svn-id: http://svn.webkit.org/repository/webkit/trunk@48336 268f45cc-cd09-0410-ab3c-d52691b4dbfc
parent de099dea
......@@ -66,7 +66,7 @@ private:
virtual bool hasInstance(ExecState* exec, JSValue value, JSValue proto);
virtual void getPropertyNames(ExecState*, PropertyNameArray&);
virtual void getOwnPropertyNames(ExecState*, PropertyNameArray&);
virtual double toNumber(ExecState*) const;
virtual UString toString(ExecState*) const;
......
......@@ -373,7 +373,7 @@ JSValue JSCallbackObject<Base>::call(ExecState* exec, JSObject* functionObject,
}
template <class Base>
void JSCallbackObject<Base>::getPropertyNames(ExecState* exec, PropertyNameArray& propertyNames)
void JSCallbackObject<Base>::getOwnPropertyNames(ExecState* exec, PropertyNameArray& propertyNames)
{
JSContextRef execRef = toRef(exec);
JSObjectRef thisRef = toRef(this);
......@@ -407,7 +407,7 @@ void JSCallbackObject<Base>::getPropertyNames(ExecState* exec, PropertyNameArray
}
}
Base::getPropertyNames(exec, propertyNames);
Base::getOwnPropertyNames(exec, propertyNames);
}
template <class Base>
......
2009-09-12 Oliver Hunt <oliver@apple.com>
Reviewed by Maciej Stachowiak.
[ES5] Implement Object.keys
https://bugs.webkit.org/show_bug.cgi?id=29170
This patch basically requires two separate steps, the first is to split getPropertyNames
into two functions -- getOwnPropertyNames and getPropertyNames, basically making them behave
in the same way as getOwnPropertySlot and getPropertySlot. In essence getOwnPropertyNames
produces the list of properties on an object excluding its prototype chain and getPropertyNames
just iterates the the object and its prototype chain calling getOwnPropertyNames at each level.
* API/JSCallbackObject.h:
* API/JSCallbackObjectFunctions.h:
(JSC::::getOwnPropertyNames):
* JavaScriptCore.exp:
* debugger/DebuggerActivation.cpp:
(JSC::DebuggerActivation::getOwnPropertyNames):
* debugger/DebuggerActivation.h:
* runtime/CommonIdentifiers.h:
* runtime/JSArray.cpp:
(JSC::JSArray::getOwnPropertyNames):
* runtime/JSArray.h:
* runtime/JSByteArray.cpp:
(JSC::JSByteArray::getOwnPropertyNames):
* runtime/JSByteArray.h:
* runtime/JSNotAnObject.cpp:
(JSC::JSNotAnObject::getOwnPropertyNames):
* runtime/JSNotAnObject.h:
* runtime/JSObject.cpp:
(JSC::JSObject::getOwnPropertyNames):
* runtime/JSObject.h:
* runtime/JSVariableObject.cpp:
(JSC::JSVariableObject::getOwnPropertyNames):
* runtime/JSVariableObject.h:
* runtime/ObjectConstructor.cpp:
(JSC::ObjectConstructor::ObjectConstructor):
(JSC::objectConstructorKeys):
* runtime/RegExpMatchesArray.h:
(JSC::RegExpMatchesArray::getOwnPropertyNames):
* runtime/StringObject.cpp:
(JSC::StringObject::getOwnPropertyNames):
* runtime/StringObject.h:
* runtime/Structure.cpp:
(JSC::Structure::getOwnEnumerablePropertyNames):
(JSC::Structure::getEnumerablePropertyNames):
* runtime/Structure.h:
2009-09-11 Oliver Hunt <oliver@apple.com>
Reviewed by Sam Weinig.
......
......@@ -113,9 +113,9 @@ __ZN3JSC12SamplingTool4dumpEPNS_9ExecStateE
__ZN3JSC12SamplingTool5setupEv
__ZN3JSC12SmallStrings17createEmptyStringEPNS_12JSGlobalDataE
__ZN3JSC12StringObject14deletePropertyEPNS_9ExecStateERKNS_10IdentifierE
__ZN3JSC12StringObject16getPropertyNamesEPNS_9ExecStateERNS_17PropertyNameArrayE
__ZN3JSC12StringObject18getOwnPropertySlotEPNS_9ExecStateERKNS_10IdentifierERNS_12PropertySlotE
__ZN3JSC12StringObject18getOwnPropertySlotEPNS_9ExecStateEjRNS_12PropertySlotE
__ZN3JSC12StringObject19getOwnPropertyNamesEPNS_9ExecStateERNS_17PropertyNameArrayE
__ZN3JSC12StringObject24getOwnPropertyDescriptorEPNS_9ExecStateERKNS_10IdentifierERNS_18PropertyDescriptorE
__ZN3JSC12StringObject3putEPNS_9ExecStateERKNS_10IdentifierENS_7JSValueERNS_15PutPropertySlotE
__ZN3JSC12StringObject4infoE
......@@ -147,7 +147,7 @@ __ZN3JSC16InternalFunction4nameEPNS_12JSGlobalDataE
__ZN3JSC16InternalFunctionC2EPNS_12JSGlobalDataEN3WTF10PassRefPtrINS_9StructureEEERKNS_10IdentifierE
__ZN3JSC16JSVariableObject14deletePropertyEPNS_9ExecStateERKNS_10IdentifierE
__ZN3JSC16JSVariableObject14symbolTableGetERKNS_10IdentifierERNS_18PropertyDescriptorE
__ZN3JSC16JSVariableObject16getPropertyNamesEPNS_9ExecStateERNS_17PropertyNameArrayE
__ZN3JSC16JSVariableObject19getOwnPropertyNamesEPNS_9ExecStateERNS_17PropertyNameArrayE
__ZN3JSC16toUInt32SlowCaseEdRb
__ZN3JSC17BytecodeGenerator21setDumpsGeneratedCodeEb
__ZN3JSC17PropertyNameArray3addEPNS_7UString3RepE
......@@ -250,6 +250,7 @@ __ZN3JSC8JSObject17putWithAttributesEPNS_9ExecStateERKNS_10IdentifierENS_7JSValu
__ZN3JSC8JSObject17putWithAttributesEPNS_9ExecStateEjNS_7JSValueEj
__ZN3JSC8JSObject18getOwnPropertySlotEPNS_9ExecStateEjRNS_12PropertySlotE
__ZN3JSC8JSObject18getPrimitiveNumberEPNS_9ExecStateERdRNS_7JSValueE
__ZN3JSC8JSObject19getOwnPropertyNamesEPNS_9ExecStateERNS_17PropertyNameArrayE
__ZN3JSC8JSObject21getPropertyDescriptorEPNS_9ExecStateERKNS_10IdentifierERNS_18PropertyDescriptorE
__ZN3JSC8JSObject22fillGetterPropertySlotERNS_12PropertySlotEPNS_7JSValueE
__ZN3JSC8JSObject23allocatePropertyStorageEmm
......
......@@ -71,7 +71,7 @@ bool DebuggerActivation::deleteProperty(ExecState* exec, const Identifier& prope
return m_activation->deleteProperty(exec, propertyName);
}
void DebuggerActivation::getPropertyNames(ExecState* exec, PropertyNameArray& propertyNames)
void DebuggerActivation::getOwnPropertyNames(ExecState* exec, PropertyNameArray& propertyNames)
{
m_activation->getPropertyNames(exec, propertyNames);
}
......
......@@ -42,7 +42,7 @@ namespace JSC {
virtual void put(ExecState*, const Identifier& propertyName, JSValue, PutPropertySlot&);
virtual void putWithAttributes(ExecState*, const Identifier& propertyName, JSValue, unsigned attributes);
virtual bool deleteProperty(ExecState*, const Identifier& propertyName);
virtual void getPropertyNames(ExecState*, PropertyNameArray&);
virtual void getOwnPropertyNames(ExecState*, PropertyNameArray&);
virtual bool getPropertyAttributes(ExecState*, const Identifier& propertyName, unsigned& attributes) const;
virtual void defineGetter(ExecState*, const Identifier& propertyName, JSObject* getterFunction);
virtual void defineSetter(ExecState*, const Identifier& propertyName, JSObject* setterFunction);
......
......@@ -53,6 +53,7 @@
macro(input) \
macro(isArray) \
macro(isPrototypeOf) \
macro(keys) \
macro(length) \
macro(message) \
macro(multiline) \
......
......@@ -464,7 +464,7 @@ bool JSArray::deleteProperty(ExecState* exec, unsigned i)
return false;
}
void JSArray::getPropertyNames(ExecState* exec, PropertyNameArray& propertyNames)
void JSArray::getOwnPropertyNames(ExecState* exec, PropertyNameArray& propertyNames)
{
// FIXME: Filling PropertyNameArray with an identifier for every integer
// is incredibly inefficient for large arrays. We need a different approach,
......@@ -484,7 +484,7 @@ void JSArray::getPropertyNames(ExecState* exec, PropertyNameArray& propertyNames
propertyNames.add(Identifier::from(exec, it->first));
}
JSObject::getPropertyNames(exec, propertyNames);
JSObject::getOwnPropertyNames(exec, propertyNames);
}
bool JSArray::increaseVectorLength(unsigned newLength)
......
......@@ -91,7 +91,7 @@ namespace JSC {
virtual void put(ExecState*, const Identifier& propertyName, JSValue, PutPropertySlot&);
virtual bool deleteProperty(ExecState*, const Identifier& propertyName);
virtual bool deleteProperty(ExecState*, unsigned propertyName);
virtual void getPropertyNames(ExecState*, PropertyNameArray&);
virtual void getOwnPropertyNames(ExecState*, PropertyNameArray&);
virtual void markChildren(MarkStack&);
void* lazyCreationData();
......
......@@ -96,12 +96,12 @@ void JSByteArray::put(ExecState* exec, unsigned propertyName, JSValue value)
setIndex(exec, propertyName, value);
}
void JSByteArray::getPropertyNames(ExecState* exec, PropertyNameArray& propertyNames)
void JSByteArray::getOwnPropertyNames(ExecState* exec, PropertyNameArray& propertyNames)
{
unsigned length = m_storage->length();
for (unsigned i = 0; i < length; ++i)
propertyNames.add(Identifier::from(exec, i));
JSObject::getPropertyNames(exec, propertyNames);
JSObject::getOwnPropertyNames(exec, propertyNames);
}
}
......
......@@ -82,7 +82,7 @@ namespace JSC {
virtual void put(JSC::ExecState*, const JSC::Identifier& propertyName, JSC::JSValue, JSC::PutPropertySlot&);
virtual void put(JSC::ExecState*, unsigned propertyName, JSC::JSValue);
virtual void getPropertyNames(JSC::ExecState*, JSC::PropertyNameArray&);
virtual void getOwnPropertyNames(JSC::ExecState*, JSC::PropertyNameArray&);
virtual const ClassInfo* classInfo() const { return m_classInfo; }
static const ClassInfo s_defaultInfo;
......
......@@ -121,7 +121,7 @@ bool JSNotAnObject::deleteProperty(ExecState* exec, unsigned)
return false;
}
void JSNotAnObject::getPropertyNames(ExecState* exec, PropertyNameArray&)
void JSNotAnObject::getOwnPropertyNames(ExecState* exec, PropertyNameArray&)
{
ASSERT_UNUSED(exec, exec->hadException() && exec->exception() == m_exception);
}
......
......@@ -88,7 +88,7 @@ namespace JSC {
virtual bool deleteProperty(ExecState*, const Identifier& propertyName);
virtual bool deleteProperty(ExecState*, unsigned propertyName);
virtual void getPropertyNames(ExecState*, PropertyNameArray&);
virtual void getOwnPropertyNames(ExecState*, PropertyNameArray&);
JSNotAnObjectErrorStub* m_exception;
};
......
......@@ -427,6 +427,11 @@ void JSObject::getPropertyNames(ExecState* exec, PropertyNameArray& propertyName
m_structure->getEnumerablePropertyNames(exec, propertyNames, this);
}
void JSObject::getOwnPropertyNames(ExecState* exec, PropertyNameArray& propertyNames)
{
m_structure->getOwnEnumerablePropertyNames(exec, propertyNames, this);
}
bool JSObject::toBoolean(ExecState*) const
{
return true;
......
......@@ -123,6 +123,7 @@ namespace JSC {
virtual bool hasInstance(ExecState*, JSValue, JSValue prototypeProperty);
virtual void getPropertyNames(ExecState*, PropertyNameArray&);
virtual void getOwnPropertyNames(ExecState*, PropertyNameArray&);
virtual JSValue toPrimitive(ExecState*, PreferredPrimitiveType = NoPreference) const;
virtual bool getPrimitiveNumber(ExecState*, double& number, JSValue& value);
......
......@@ -42,7 +42,7 @@ bool JSVariableObject::deleteProperty(ExecState* exec, const Identifier& propert
return JSObject::deleteProperty(exec, propertyName);
}
void JSVariableObject::getPropertyNames(ExecState* exec, PropertyNameArray& propertyNames)
void JSVariableObject::getOwnPropertyNames(ExecState* exec, PropertyNameArray& propertyNames)
{
SymbolTable::const_iterator end = symbolTable().end();
for (SymbolTable::const_iterator it = symbolTable().begin(); it != end; ++it) {
......@@ -50,7 +50,7 @@ void JSVariableObject::getPropertyNames(ExecState* exec, PropertyNameArray& prop
propertyNames.add(Identifier(exec, it->first.get()));
}
JSObject::getPropertyNames(exec, propertyNames);
JSObject::getOwnPropertyNames(exec, propertyNames);
}
bool JSVariableObject::getPropertyAttributes(ExecState* exec, const Identifier& propertyName, unsigned& attributes) const
......
......@@ -49,7 +49,7 @@ namespace JSC {
virtual void putWithAttributes(ExecState*, const Identifier&, JSValue, unsigned attributes) = 0;
virtual bool deleteProperty(ExecState*, const Identifier&);
virtual void getPropertyNames(ExecState*, PropertyNameArray&);
virtual void getOwnPropertyNames(ExecState*, PropertyNameArray&);
virtual bool isVariableObject() const;
virtual bool isDynamicScope() const = 0;
......
......@@ -34,6 +34,7 @@ ASSERT_CLASS_FITS_IN_CELL(ObjectConstructor);
static JSValue JSC_HOST_CALL objectConstructorGetPrototypeOf(ExecState*, JSObject*, JSValue, const ArgList&);
static JSValue JSC_HOST_CALL objectConstructorGetOwnPropertyDescriptor(ExecState*, JSObject*, JSValue, const ArgList&);
static JSValue JSC_HOST_CALL objectConstructorKeys(ExecState*, JSObject*, JSValue, const ArgList&);
ObjectConstructor::ObjectConstructor(ExecState* exec, PassRefPtr<Structure> structure, ObjectPrototype* objectPrototype, Structure* prototypeFunctionStructure)
: InternalFunction(&exec->globalData(), structure, Identifier(exec, "Object"))
......@@ -46,6 +47,7 @@ ObjectConstructor::ObjectConstructor(ExecState* exec, PassRefPtr<Structure> stru
putDirectFunctionWithoutTransition(exec, new (exec) NativeFunctionWrapper(exec, prototypeFunctionStructure, 1, exec->propertyNames().getPrototypeOf, objectConstructorGetPrototypeOf), DontEnum);
putDirectFunctionWithoutTransition(exec, new (exec) NativeFunctionWrapper(exec, prototypeFunctionStructure, 2, exec->propertyNames().getOwnPropertyDescriptor, objectConstructorGetOwnPropertyDescriptor), DontEnum);
putDirectFunctionWithoutTransition(exec, new (exec) NativeFunctionWrapper(exec, prototypeFunctionStructure, 1, exec->propertyNames().keys, objectConstructorKeys), DontEnum);
}
// ECMA 15.2.2
......@@ -116,4 +118,17 @@ JSValue JSC_HOST_CALL objectConstructorGetOwnPropertyDescriptor(ExecState* exec,
return description;
}
JSValue JSC_HOST_CALL objectConstructorKeys(ExecState* exec, JSObject*, JSValue, const ArgList& args)
{
if (!args.at(0).isObject())
return throwError(exec, TypeError, "Requested keys of a value that is not an object.");
PropertyNameArray properties(exec);
asObject(args.at(0))->getOwnPropertyNames(exec, properties);
JSArray* keys = constructEmptyArray(exec);
size_t numProperties = properties.size();
for (size_t i = 0; i < numProperties; i++)
keys->push(exec, jsOwnedString(exec, properties[i].ustring()));
return keys;
}
} // namespace JSC
......@@ -79,11 +79,11 @@ namespace JSC {
return JSArray::deleteProperty(exec, propertyName);
}
virtual void getPropertyNames(ExecState* exec, PropertyNameArray& arr)
virtual void getOwnPropertyNames(ExecState* exec, PropertyNameArray& arr)
{
if (lazyCreationData())
fillArrayInstance(exec);
JSArray::getPropertyNames(exec, arr);
JSArray::getOwnPropertyNames(exec, arr);
}
void fillArrayInstance(ExecState*);
......
......@@ -82,12 +82,12 @@ bool StringObject::deleteProperty(ExecState* exec, const Identifier& propertyNam
return JSObject::deleteProperty(exec, propertyName);
}
void StringObject::getPropertyNames(ExecState* exec, PropertyNameArray& propertyNames)
void StringObject::getOwnPropertyNames(ExecState* exec, PropertyNameArray& propertyNames)
{
int size = internalValue()->value().size();
for (int i = 0; i < size; ++i)
propertyNames.add(Identifier(exec, UString::from(i)));
return JSObject::getPropertyNames(exec, propertyNames);
return JSObject::getOwnPropertyNames(exec, propertyNames);
}
} // namespace JSC
......@@ -39,7 +39,7 @@ namespace JSC {
virtual void put(ExecState* exec, const Identifier& propertyName, JSValue, PutPropertySlot&);
virtual bool deleteProperty(ExecState*, const Identifier& propertyName);
virtual void getPropertyNames(ExecState*, PropertyNameArray&);
virtual void getOwnPropertyNames(ExecState*, PropertyNameArray&);
virtual const ClassInfo* classInfo() const { return &info; }
static const JS_EXPORTDATA ClassInfo info;
......
......@@ -273,6 +273,12 @@ void Structure::materializePropertyMap()
}
}
void Structure::getOwnEnumerablePropertyNames(ExecState* exec, PropertyNameArray& propertyNames, JSObject* baseObject)
{
getEnumerableNamesFromPropertyTable(propertyNames);
getEnumerableNamesFromClassInfoTable(exec, baseObject->classInfo(), propertyNames);
}
void Structure::getEnumerablePropertyNames(ExecState* exec, PropertyNameArray& propertyNames, JSObject* baseObject)
{
bool shouldCache = propertyNames.shouldCache() && !(propertyNames.size() || m_isDictionary);
......@@ -285,12 +291,22 @@ void Structure::getEnumerablePropertyNames(ExecState* exec, PropertyNameArray& p
clearEnumerationCache();
}
getEnumerableNamesFromPropertyTable(propertyNames);
getEnumerableNamesFromClassInfoTable(exec, baseObject->classInfo(), propertyNames);
baseObject->getOwnPropertyNames(exec, propertyNames);
if (m_prototype.isObject()) {
propertyNames.setShouldCache(false); // No need for our prototypes to waste memory on caching, since they're not being enumerated directly.
asObject(m_prototype)->getPropertyNames(exec, propertyNames);
JSObject* prototype = asObject(m_prototype);
while(1) {
if (!prototype->structure()->typeInfo().hasDefaultGetPropertyNames()) {
prototype->getPropertyNames(exec, propertyNames);
break;
}
prototype->getOwnPropertyNames(exec, propertyNames);
JSValue nextProto = prototype->prototype();
if (!nextProto.isObject())
break;
prototype = asObject(nextProto);
}
}
if (shouldCache) {
......
......@@ -114,6 +114,7 @@ namespace JSC {
}
void getEnumerablePropertyNames(ExecState*, PropertyNameArray&, JSObject*);
void getOwnEnumerablePropertyNames(ExecState*, PropertyNameArray&, JSObject*);
bool hasGetterSetterProperties() const { return m_hasGetterSetterProperties; }
void setHasGetterSetterProperties(bool hasGetterSetterProperties) { m_hasGetterSetterProperties = hasGetterSetterProperties; }
......
2009-09-12 Oliver Hunt <oliver@apple.com>
Reviewed by Maciej Stachowiak.
[ES5] Implement Object.keys
https://bugs.webkit.org/show_bug.cgi?id=29170
Switch over to getOwnPropertyNames instead of getPropertyNames.
* UserObjectImp.cpp:
(UserObjectImp::getOwnPropertyNames):
* UserObjectImp.h:
2009-09-02 Darin Adler <darin@apple.com>
Reviewed by Geoff Garen.
......
......@@ -94,7 +94,7 @@ JSValue UserObjectImp::callAsFunction(ExecState *exec, JSObject *thisObj, const
}
void UserObjectImp::getPropertyNames(ExecState *exec, PropertyNameArray& propertyNames)
void UserObjectImp::getOwnPropertyNames(ExecState *exec, PropertyNameArray& propertyNames)
{
JSUserObject* ptr = GetJSUserObject();
if (ptr) {
......@@ -109,7 +109,7 @@ void UserObjectImp::getPropertyNames(ExecState *exec, PropertyNameArray& propert
CFRelease(cfPropertyNames);
}
}
JSObject::getPropertyNames(exec, propertyNames);
JSObject::getOwnPropertyNames(exec, propertyNames);
}
JSValue UserObjectImp::userObjectGetter(ExecState*, const Identifier& propertyName, const PropertySlot& slot)
......
......@@ -44,7 +44,7 @@ public:
virtual CallType getCallData(CallData&);
virtual void getPropertyNames(ExecState*, PropertyNameArray&);
virtual void getOwnPropertyNames(ExecState*, PropertyNameArray&);
virtual JSValue callAsFunction(ExecState *exec, JSObject *thisObj, const ArgList &args);
virtual bool getOwnPropertySlot(ExecState *, const Identifier&, PropertySlot&);
......
2009-09-12 Oliver Hunt <oliver@apple.com>
Reviewed by Maciej Stachowiak.
[ES5] Implement Object.keys
https://bugs.webkit.org/show_bug.cgi?id=29170
Add tests for Object.keys(o), both standard usage and cross origin.
* fast/js/Object-keys-expected.txt: Added.
* fast/js/Object-keys.html: Added.
* fast/js/resources/Object-keys.js: Added.
* http/tests/security/cross-frame-access-enumeration-expected.txt:
* http/tests/security/cross-frame-access-enumeration.html:
2009-09-12 Sam Weinig <sam@webkit.org>
Reviewed by Anders Carlsson.
......
Test to ensure correct behaviour of Object.keys
On success, you will see a series of "PASS" messages, followed by "TEST COMPLETE".
PASS Object.keys({}) is []
PASS Object.keys({a:null}) is ['a']
PASS Object.keys({a:null, b:null}) is ['a', 'b']
PASS Object.keys({b:null, a:null}) is ['b', 'a']
PASS Object.keys([]) is []
PASS Object.keys([null]) is ['0']
PASS Object.keys([null,null]) is ['0','1']
PASS Object.keys([null,null,,,,null]) is ['0','1','5']
PASS Object.keys({__proto__:{a:null}}) is []
PASS Object.keys({__proto__:[1,2,3]}) is []
PASS x=[];x.__proto__=[1,2,3];Object.keys(x) is []
PASS successfullyParsed is true
TEST COMPLETE
<!DOCTYPE HTML PUBLIC "-//IETF//DTD HTML//EN">
<html>
<head>
<link rel="stylesheet" href="resources/js-test-style.css">
<script src="resources/js-test-pre.js"></script>
</head>
<body>
<p id="description"></p>
<div id="console"></div>
<script src="resources/Object-keys.js"></script>
<script src="resources/js-test-post.js"></script>
</body>
</html>
description("Test to ensure correct behaviour of Object.keys");
shouldBe("Object.keys({})", "[]");
shouldBe("Object.keys({a:null})", "['a']");
shouldBe("Object.keys({a:null, b:null})", "['a', 'b']");
shouldBe("Object.keys({b:null, a:null})", "['b', 'a']");
shouldBe("Object.keys([])", "[]");
shouldBe("Object.keys([null])", "['0']");
shouldBe("Object.keys([null,null])", "['0','1']");
shouldBe("Object.keys([null,null,,,,null])", "['0','1','5']");
shouldBe("Object.keys({__proto__:{a:null}})", "[]");
shouldBe("Object.keys({__proto__:[1,2,3]})", "[]");
shouldBe("x=[];x.__proto__=[1,2,3];Object.keys(x)", "[]");
successfullyParsed = true;
......@@ -4,10 +4,19 @@ CONSOLE MESSAGE: line 1: Unsafe JavaScript attempt to access frame with URL http
CONSOLE MESSAGE: line 1: Unsafe JavaScript attempt to access frame with URL http://localhost:8000/security/resources/cross-frame-iframe-for-enumeration-test.html from frame with URL http://127.0.0.1:8000/security/cross-frame-access-enumeration.html. Domains, protocols and ports must match.
CONSOLE MESSAGE: line 1: Unsafe JavaScript attempt to access frame with URL http://localhost:8000/security/resources/cross-frame-iframe-for-enumeration-test.html from frame with URL http://127.0.0.1:8000/security/cross-frame-access-enumeration.html. Domains, protocols and ports must match.
CONSOLE MESSAGE: line 1: Unsafe JavaScript attempt to access frame with URL http://localhost:8000/security/resources/cross-frame-iframe-for-enumeration-test.html from frame with URL http://127.0.0.1:8000/security/cross-frame-access-enumeration.html. Domains, protocols and ports must match.
CONSOLE MESSAGE: line 1: Unsafe JavaScript attempt to access frame with URL http://localhost:8000/security/resources/cross-frame-iframe-for-enumeration-test.html from frame with URL http://127.0.0.1:8000/security/cross-frame-access-enumeration.html. Domains, protocols and ports must match.
This tests that variable names can't be enumerated cross domain (see http://bugs.webkit.org/show_bug.cgi?id=16387)
PASS: Cross frame access by enumerating the window object was denied.
PASS: Cross frame access by getting the keys of the window object was denied.
PASS: Cross frame access by enumerating the History object was denied.
PASS: Cross frame access by getting the keys of the History object was denied.
PASS: Cross frame access by enumerating the Location object was denied.
PASS: Cross frame access by getting the keys of the Location object was denied.
......@@ -45,6 +45,13 @@
}
log("PASS: Cross frame access by enumerating the window object was denied.");
var b_winKeys = Object.keys(b_win);
if (b_winKeys.indexOf("customWindowProperty") != -1) {
log("FAIL: Cross frame access by getting the keys of the window object was allowed.");
return;
}
log("PASS: Cross frame access by getting the keys of the window object was denied.");
// Test enumerating the History object
var b_win_history = b_win.history;
try {
......@@ -58,6 +65,13 @@
}
log("PASS: Cross frame access by enumerating the History object was denied.");
var b_winHistoryKeys = Object.keys(b_win_history);
if (b_winHistoryKeys.indexOf("customHistoryProperty") != -1) {
log("FAIL: Cross frame access by getting the keys of the History object was allowed.");
return;
}
log("PASS: Cross frame access by getting the keys of the History object was denied.");
// Test enumerating the Location object
var b_win_location = b_win.location;
try {
......@@ -70,6 +84,13 @@
} catch (e) {
}
log("PASS: Cross frame access by enumerating the Location object was denied.");
var b_winLocationKeys = Object.keys(b_win_location);
if (b_winLocationKeys.indexOf("customLocationProperty") != -1) {
log("FAIL: Cross frame access by getting the keys of the Location object was allowed.");
return;
}
log("PASS: Cross frame access by getting the keys of the Location object was denied.");
}
</script>
</head>
......
2009-09-12 Oliver Hunt <oliver@apple.com>
Reviewed by Maciej Stachowiak.
[ES5] Implement Object.keys
https://bugs.webkit.org/show_bug.cgi?id=29170
Switch from getPropertyNames to getOwnPropertyNames, and provide custom
getPropertyNames to DOMWindow, DOMWindowShell and QuarantinedObjectWrapper
in order to ensure correct semantics are maintained.
Test: fast/js/Object-keys.html
* bindings/js/JSDOMWindowCustom.cpp:
(WebCore::JSDOMWindow::getOwnPropertyNames):
* bindings/js/JSDOMWindowShell.cpp:
(WebCore::JSDOMWindowShell::getOwnPropertyNames):
* bindings/js/JSDOMWindowShell.h:
* bindings/js/JSHistoryCustom.cpp:
(WebCore::JSHistory::getOwnPropertyNames):
* bindings/js/JSLocationCustom.cpp:
(WebCore::JSLocation::getOwnPropertyNames):
* bindings/js/JSQuarantinedObjectWrapper.cpp:
(WebCore::JSQuarantinedObjectWrapper::getPropertyNames):
(WebCore::JSQuarantinedObjectWrapper::getOwnPropertyNames):
* bindings/js/JSQuarantinedObjectWrapper.h:
* bindings/js/JSStorageCustom.cpp:
(WebCore::JSStorage::getOwnPropertyNames):
* bindings/scripts/CodeGeneratorJS.pm:
* bridge/runtime_object.cpp:
(JSC::RuntimeObjectImp::getPropertyNames):
(JSC::RuntimeObjectImp::getOwnPropertyNames):
* bridge/runtime_object.h:
2009-09-12 Sam Weinig <sam@webkit.org>
Reviewed by Anders Carlsson.
......@@ -472,6 +472,14 @@ void JSDOMWindow::getPropertyNames(ExecState* exec, PropertyNameArray& propertyN
Base::getPropertyNames(exec, propertyNames);
}
void JSDOMWindow::getOwnPropertyNames(ExecState* exec, PropertyNameArray& propertyNames)
{
// Only allow the window to enumerated by frames in the same origin.
if (!allowsAccessFrom(exec))
return;
Base::getOwnPropertyNames(exec, propertyNames);
}
bool JSDOMWindow::getPropertyAttributes(ExecState* exec, const Identifier& propertyName, unsigned& attributes) const
{
// Only allow getting property attributes properties by frames in the same origin.
......