Commit 4b4f785d authored by oliver@apple.com's avatar oliver@apple.com

[ES5] Implement getOwnPropertyDescriptor

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

Reviewed by Gavin Barraclough.

JavaScriptCore:
Implement the core runtime support for getOwnPropertyDescriptor.
This adds a virtual getOwnPropertyDescriptor method to every class
that implements getOwnPropertySlot that shadows the behaviour of
getOwnPropertySlot.  The alternative would be to make getOwnPropertySlot
(or PropertySlots in general) provide property attribute information,
but quick testing showed this to be a regression.

WebCore:
Implement the WebCore side of getOwnPropertyDescriptor.  This
requires a custom implementation of getOwnPropertyDescriptor
for every class with a custom implementation of getOwnPropertySlot.

The bindings generator has been updated to generate appropriate
versions of getOwnPropertyDescriptor for the general case where
a custom getOwnPropertyDescriptor is not needed.  ES5 is vague
about how getOwnPropertyDescriptor should work in the context of
"host" functions with polymorphic [[GetOwnProperty]], so it seems
okay that occasionally we "guess" what attributes -- eg. determining
whether a property is writable.

Test: fast/js/getOwnPropertyDescriptor.html

git-svn-id: http://svn.webkit.org/repository/webkit/trunk@47780 268f45cc-cd09-0410-ab3c-d52691b4dbfc
parent 8961a506
2009-08-25 Oliver Hunt <oliver@apple.com>
Reviewed by Gavin Barraclough.
[ES5] Implement getOwnPropertyDescriptor
https://bugs.webkit.org/show_bug.cgi?id=28724
Implement the core runtime support for getOwnPropertyDescriptor.
This adds a virtual getOwnPropertyDescriptor method to every class
that implements getOwnPropertySlot that shadows the behaviour of
getOwnPropertySlot. The alternative would be to make getOwnPropertySlot
(or PropertySlots in general) provide property attribute information,
but quick testing showed this to be a regression.
* JavaScriptCore.exp:
* JavaScriptCore.xcodeproj/project.pbxproj:
* runtime/Arguments.cpp:
(JSC::Arguments::getOwnPropertyDescriptor):
* runtime/Arguments.h:
* runtime/ArrayPrototype.cpp:
(JSC::ArrayPrototype::getOwnPropertyDescriptor):
* runtime/ArrayPrototype.h:
* runtime/CommonIdentifiers.h:
* runtime/DatePrototype.cpp:
(JSC::DatePrototype::getOwnPropertyDescriptor):
* runtime/DatePrototype.h:
* runtime/JSArray.cpp:
(JSC::JSArray::getOwnPropertyDescriptor):
* runtime/JSArray.h:
* runtime/JSByteArray.cpp:
(JSC::JSByteArray::getOwnPropertyDescriptor):
* runtime/JSByteArray.h:
* runtime/JSFunction.cpp:
(JSC::JSFunction::getOwnPropertyDescriptor):
* runtime/JSFunction.h:
* runtime/JSGlobalObject.h:
(JSC::JSGlobalObject::getOwnPropertyDescriptor):
* runtime/JSNotAnObject.cpp:
(JSC::JSNotAnObject::getOwnPropertyDescriptor):
* runtime/JSNotAnObject.h:
* runtime/JSONObject.cpp:
(JSC::JSONObject::getOwnPropertySlot):
(JSC::JSONObject::getOwnPropertyDescriptor):
* runtime/JSONObject.h:
* runtime/JSObject.cpp:
(JSC::JSObject::getOwnPropertyDescriptor):
(JSC::JSObject::getPropertyDescriptor):
* runtime/JSObject.h:
* runtime/JSString.cpp:
(JSC::JSString::getStringPropertyDescriptor):
(JSC::JSString::getOwnPropertyDescriptor):
* runtime/JSString.h:
* runtime/JSVariableObject.cpp:
(JSC::JSVariableObject::symbolTableGet):
* runtime/JSVariableObject.h:
* runtime/Lookup.h:
(JSC::getStaticPropertyDescriptor):
(JSC::getStaticFunctionDescriptor):
(JSC::getStaticValueDescriptor):
Add property descriptor equivalents of the lookup
table access functions
* runtime/MathObject.cpp:
(JSC::MathObject::getOwnPropertySlot):
(JSC::MathObject::getOwnPropertyDescriptor):
* runtime/MathObject.h:
* runtime/NumberConstructor.cpp:
(JSC::NumberConstructor::getOwnPropertyDescriptor):
* runtime/NumberConstructor.h:
* runtime/ObjectConstructor.cpp:
(JSC::ObjectConstructor::ObjectConstructor):
(JSC::objectConstructorGetOwnPropertyDescriptor):
* runtime/PropertyDescriptor.cpp: Added.
(JSC::PropertyDescriptor::writable):
(JSC::PropertyDescriptor::enumerable):
(JSC::PropertyDescriptor::configurable):
(JSC::PropertyDescriptor::hasAccessors):
(JSC::PropertyDescriptor::setUndefined):
(JSC::PropertyDescriptor::getter):
(JSC::PropertyDescriptor::setter):
(JSC::PropertyDescriptor::setDescriptor):
(JSC::PropertyDescriptor::setAccessorDescriptor):
* runtime/PropertyDescriptor.h: Added.
(JSC::PropertyDescriptor::PropertyDescriptor):
(JSC::PropertyDescriptor::attributes):
(JSC::PropertyDescriptor::isValid):
(JSC::PropertyDescriptor::value):
* runtime/RegExpConstructor.cpp:
(JSC::RegExpConstructor::getOwnPropertyDescriptor):
* runtime/RegExpConstructor.h:
* runtime/RegExpMatchesArray.h:
(JSC::RegExpMatchesArray::getOwnPropertyDescriptor):
* runtime/RegExpObject.cpp:
(JSC::RegExpObject::getOwnPropertyDescriptor):
* runtime/RegExpObject.h:
* runtime/StringObject.cpp:
(JSC::StringObject::getOwnPropertyDescriptor):
* runtime/StringObject.h:
* runtime/StringPrototype.cpp:
(JSC::StringPrototype::getOwnPropertyDescriptor):
* runtime/StringPrototype.h:
2009-08-24 Gavin Barraclough <barraclough@apple.com>
Reviewed by Darin Adler.
......
......@@ -117,6 +117,7 @@ __ZN3JSC12StringObject14toThisJSStringEPNS_9ExecStateE
__ZN3JSC12StringObject16getPropertyNamesEPNS_9ExecStateERNS_17PropertyNameArrayE
__ZN3JSC12StringObject18getOwnPropertySlotEPNS_9ExecStateERKNS_10IdentifierERNS_12PropertySlotE
__ZN3JSC12StringObject18getOwnPropertySlotEPNS_9ExecStateEjRNS_12PropertySlotE
__ZN3JSC12StringObject24getOwnPropertyDescriptorEPNS_9ExecStateERKNS_10IdentifierERNS_18PropertyDescriptorE
__ZN3JSC12StringObject3putEPNS_9ExecStateERKNS_10IdentifierENS_7JSValueERNS_15PutPropertySlotE
__ZN3JSC12StringObject4infoE
__ZN3JSC12StringObjectC2EPNS_9ExecStateEN3WTF10PassRefPtrINS_9StructureEEERKNS_7UStringE
......@@ -146,6 +147,7 @@ __ZN3JSC16InternalFunction4infoE
__ZN3JSC16InternalFunction4nameEPNS_12JSGlobalDataE
__ZN3JSC16InternalFunctionC2EPNS_12JSGlobalDataEN3WTF10PassRefPtrINS_9StructureEEERKNS_10IdentifierE
__ZN3JSC16JSVariableObject14deletePropertyEPNS_9ExecStateERKNS_10IdentifierE
__ZN3JSC16JSVariableObject14symbolTableGetERKNS_10IdentifierERNS_18PropertyDescriptorE
__ZN3JSC16JSVariableObject16getPropertyNamesEPNS_9ExecStateERNS_17PropertyNameArrayE
__ZN3JSC16toUInt32SlowCaseEdRb
__ZN3JSC17BytecodeGenerator21setDumpsGeneratedCodeEb
......@@ -154,6 +156,11 @@ __ZN3JSC17PrototypeFunctionC1EPNS_9ExecStateEN3WTF10PassRefPtrINS_9StructureEEEi
__ZN3JSC17PrototypeFunctionC1EPNS_9ExecStateEiRKNS_10IdentifierEPFNS_7JSValueES2_PNS_8JSObjectES6_RKNS_7ArgListEE
__ZN3JSC17constructFunctionEPNS_9ExecStateERKNS_7ArgListERKNS_10IdentifierERKNS_7UStringEi
__ZN3JSC18DebuggerActivationC1EPNS_8JSObjectE
__ZN3JSC18PropertyDescriptor12setUndefinedEv
__ZN3JSC18PropertyDescriptor13setDescriptorENS_7JSValueEj
__ZN3JSC18PropertyDescriptor21setAccessorDescriptorENS_7JSValueES1_j
__ZNK3JSC18PropertyDescriptor6setterEv
__ZNK3JSC18PropertyDescriptor6getterEv
__ZN3JSC19constructEmptyArrayEPNS_9ExecStateE
__ZN3JSC19initializeThreadingEv
__ZN3JSC20MarkedArgumentBuffer10slowAppendENS_7JSValueE
......@@ -244,8 +251,10 @@ __ZN3JSC8JSObject17putWithAttributesEPNS_9ExecStateERKNS_10IdentifierENS_7JSValu
__ZN3JSC8JSObject17putWithAttributesEPNS_9ExecStateEjNS_7JSValueEj
__ZN3JSC8JSObject18getOwnPropertySlotEPNS_9ExecStateEjRNS_12PropertySlotE
__ZN3JSC8JSObject18getPrimitiveNumberEPNS_9ExecStateERdRNS_7JSValueE
__ZN3JSC8JSObject21getPropertyDescriptorEPNS_9ExecStateERKNS_10IdentifierERNS_18PropertyDescriptorE
__ZN3JSC8JSObject22fillGetterPropertySlotERNS_12PropertySlotEPNS_7JSValueE
__ZN3JSC8JSObject23allocatePropertyStorageEmm
__ZN3JSC8JSObject24getOwnPropertyDescriptorEPNS_9ExecStateERKNS_10IdentifierERNS_18PropertyDescriptorE
__ZN3JSC8JSObject3putEPNS_9ExecStateERKNS_10IdentifierENS_7JSValueERNS_15PutPropertySlotE
__ZN3JSC8JSObject3putEPNS_9ExecStateEjNS_7JSValueE
__ZN3JSC8Profiler13stopProfilingEPNS_9ExecStateERKNS_7UStringE
......@@ -337,6 +346,7 @@ __ZNK3JSC17DebuggerCallFrame12functionNameEv
__ZNK3JSC17DebuggerCallFrame22calculatedFunctionNameEv
__ZNK3JSC17DebuggerCallFrame4typeEv
__ZNK3JSC17DebuggerCallFrame8evaluateERKNS_7UStringERNS_7JSValueE
__ZNK3JSC18PropertyDescriptor12hasAccessorsEv
__ZNK3JSC4Heap10statisticsEv
__ZNK3JSC6JSCell12toThisObjectEPNS_9ExecStateE
__ZNK3JSC6JSCell12toThisStringEPNS_9ExecStateE
......
......@@ -215,6 +215,8 @@
A7E2EA6C0FB460CF00601F06 /* LiteralParser.cpp in Sources */ = {isa = PBXBuildFile; fileRef = A7E2EA6A0FB460CF00601F06 /* LiteralParser.cpp */; };
A7F9935F0FD7325100A0B2D0 /* JSONObject.h in Headers */ = {isa = PBXBuildFile; fileRef = A7F9935D0FD7325100A0B2D0 /* JSONObject.h */; };
A7F993600FD7325100A0B2D0 /* JSONObject.cpp in Sources */ = {isa = PBXBuildFile; fileRef = A7F9935E0FD7325100A0B2D0 /* JSONObject.cpp */; };
A7FB60A4103F7DC20017A286 /* PropertyDescriptor.cpp in Sources */ = {isa = PBXBuildFile; fileRef = A7FB60A3103F7DC20017A286 /* PropertyDescriptor.cpp */; };
A7FB61001040C38B0017A286 /* PropertyDescriptor.h in Headers */ = {isa = PBXBuildFile; fileRef = A7FB604B103F5EAB0017A286 /* PropertyDescriptor.h */; settings = {ATTRIBUTES = (Private, ); }; };
BC02E90D0E1839DB000F9297 /* ErrorConstructor.h in Headers */ = {isa = PBXBuildFile; fileRef = BC02E9050E1839DB000F9297 /* ErrorConstructor.h */; };
BC02E90F0E1839DB000F9297 /* ErrorPrototype.h in Headers */ = {isa = PBXBuildFile; fileRef = BC02E9070E1839DB000F9297 /* ErrorPrototype.h */; };
BC02E9110E1839DB000F9297 /* NativeErrorConstructor.h in Headers */ = {isa = PBXBuildFile; fileRef = BC02E9090E1839DB000F9297 /* NativeErrorConstructor.h */; };
......@@ -768,6 +770,8 @@
A7F9935D0FD7325100A0B2D0 /* JSONObject.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = JSONObject.h; sourceTree = "<group>"; };
A7F9935E0FD7325100A0B2D0 /* JSONObject.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = JSONObject.cpp; sourceTree = "<group>"; };
A7F9949A0FD746A300A0B2D0 /* JSONObject.lut.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = JSONObject.lut.h; path = /Users/oliver/builds/Debug/DerivedSources/JavaScriptCore/JSONObject.lut.h; sourceTree = "<absolute>"; };
A7FB604B103F5EAB0017A286 /* PropertyDescriptor.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = PropertyDescriptor.h; sourceTree = "<group>"; };
A7FB60A3103F7DC20017A286 /* PropertyDescriptor.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = PropertyDescriptor.cpp; sourceTree = "<group>"; };
A8E894310CD0602400367179 /* JSCallbackObjectFunctions.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = JSCallbackObjectFunctions.h; sourceTree = "<group>"; };
A8E894330CD0603F00367179 /* JSGlobalObject.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = JSGlobalObject.h; sourceTree = "<group>"; };
BC02E9040E1839DB000F9297 /* ErrorConstructor.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = ErrorConstructor.cpp; sourceTree = "<group>"; };
......@@ -1338,6 +1342,7 @@
7EF6E0BB0EB7A1EC0079AFAF /* runtime */ = {
isa = PBXGroup;
children = (
A7FB604B103F5EAB0017A286 /* PropertyDescriptor.h */,
BCF605110E203EF800B9A64D /* ArgList.cpp */,
BCF605120E203EF800B9A64D /* ArgList.h */,
BC257DE50E1F51C50016B6C9 /* Arguments.cpp */,
......@@ -1510,6 +1515,7 @@
A779558F101A74D500114E55 /* MarkStack.h */,
A7C530E3102A3813005BC741 /* MarkStackPosix.cpp */,
A74B3498102A5F8E0032AB98 /* MarkStack.cpp */,
A7FB60A3103F7DC20017A286 /* PropertyDescriptor.cpp */,
);
path = runtime;
sourceTree = "<group>";
......@@ -1915,6 +1921,7 @@
A7D649AA1015224E009B2E1B /* PossiblyNull.h in Headers */,
86CAFEE31035DDE60028A609 /* Executable.h in Headers */,
142D3939103E4560007DCB52 /* NumericStrings.h in Headers */,
A7FB61001040C38B0017A286 /* PropertyDescriptor.h in Headers */,
);
runOnlyForDeploymentPostprocessing = 0;
};
......@@ -2284,6 +2291,7 @@
A7C530E4102A3813005BC741 /* MarkStackPosix.cpp in Sources */,
A74B3499102A5F8E0032AB98 /* MarkStack.cpp in Sources */,
86CA032E1038E8440028A609 /* Executable.cpp in Sources */,
A7FB60A4103F7DC20017A286 /* PropertyDescriptor.cpp in Sources */,
);
runOnlyForDeploymentPostprocessing = 0;
};
......
......@@ -179,6 +179,31 @@ bool Arguments::getOwnPropertySlot(ExecState* exec, const Identifier& propertyNa
return JSObject::getOwnPropertySlot(exec, propertyName, slot);
}
bool Arguments::getOwnPropertyDescriptor(ExecState* exec, const Identifier& propertyName, PropertyDescriptor& descriptor)
{
bool isArrayIndex;
unsigned i = propertyName.toArrayIndex(&isArrayIndex);
if (isArrayIndex && i < d->numArguments && (!d->deletedArguments || !d->deletedArguments[i])) {
if (i < d->numParameters) {
descriptor.setDescriptor(d->registers[d->firstParameterIndex + i].jsValue(), DontEnum);
} else
descriptor.setDescriptor(d->extraArguments[i - d->numParameters].jsValue(), DontEnum);
return true;
}
if (propertyName == exec->propertyNames().length && LIKELY(!d->overrodeLength)) {
descriptor.setDescriptor(jsNumber(exec, d->numArguments), DontEnum);
return true;
}
if (propertyName == exec->propertyNames().callee && LIKELY(!d->overrodeCallee)) {
descriptor.setDescriptor(d->callee, DontEnum);
return true;
}
return JSObject::getOwnPropertyDescriptor(exec, propertyName, descriptor);
}
void Arguments::put(ExecState* exec, unsigned i, JSValue value, PutPropertySlot& slot)
{
if (i < d->numArguments && (!d->deletedArguments || !d->deletedArguments[i])) {
......
......@@ -92,6 +92,7 @@ namespace JSC {
void getArgumentsData(CallFrame*, JSFunction*&, ptrdiff_t& firstParameterIndex, Register*& argv, int& argc);
virtual bool getOwnPropertySlot(ExecState*, const Identifier& propertyName, PropertySlot&);
virtual bool getOwnPropertySlot(ExecState*, unsigned propertyName, PropertySlot&);
virtual bool getOwnPropertyDescriptor(ExecState*, const Identifier&, PropertyDescriptor&);
virtual void put(ExecState*, const Identifier& propertyName, JSValue, PutPropertySlot&);
virtual void put(ExecState*, unsigned propertyName, JSValue, PutPropertySlot&);
virtual bool deleteProperty(ExecState*, const Identifier& propertyName);
......
......@@ -125,6 +125,11 @@ bool ArrayPrototype::getOwnPropertySlot(ExecState* exec, const Identifier& prope
return getStaticFunctionSlot<JSArray>(exec, ExecState::arrayTable(exec), this, propertyName, slot);
}
bool ArrayPrototype::getOwnPropertyDescriptor(ExecState* exec, const Identifier& propertyName, PropertyDescriptor& descriptor)
{
return getStaticFunctionDescriptor<JSArray>(exec, ExecState::arrayTable(exec), this, propertyName, descriptor);
}
// ------------------------------ Array Functions ----------------------------
// Helper function
......
......@@ -31,6 +31,7 @@ namespace JSC {
explicit ArrayPrototype(PassRefPtr<Structure>);
bool getOwnPropertySlot(ExecState*, const Identifier&, PropertySlot&);
virtual bool getOwnPropertyDescriptor(ExecState*, const Identifier&, PropertyDescriptor&);
virtual const ClassInfo* classInfo() const { return &info; }
static const ClassInfo info;
......
......@@ -37,12 +37,16 @@
macro(callee) \
macro(caller) \
macro(compile) \
macro(configurable) \
macro(constructor) \
macro(enumerable) \
macro(eval) \
macro(exec) \
macro(fromCharCode) \
macro(global) \
macro(get) \
macro(getPrototypeOf) \
macro(getOwnPropertyDescriptor) \
macro(hasOwnProperty) \
macro(ignoreCase) \
macro(index) \
......@@ -57,6 +61,7 @@
macro(parse) \
macro(propertyIsEnumerable) \
macro(prototype) \
macro(set) \
macro(source) \
macro(test) \
macro(toExponential) \
......@@ -67,7 +72,9 @@
macro(toPrecision) \
macro(toString) \
macro(UTC) \
macro(value) \
macro(valueOf) \
macro(writable) \
macro(displayName)
namespace JSC {
......
......@@ -407,6 +407,12 @@ bool DatePrototype::getOwnPropertySlot(ExecState* exec, const Identifier& proper
return getStaticFunctionSlot<JSObject>(exec, ExecState::dateTable(exec), this, propertyName, slot);
}
bool DatePrototype::getOwnPropertyDescriptor(ExecState* exec, const Identifier& propertyName, PropertyDescriptor& descriptor)
{
return getStaticFunctionDescriptor<JSObject>(exec, ExecState::dateTable(exec), this, propertyName, descriptor);
}
// Functions
JSValue JSC_HOST_CALL dateProtoFuncToString(ExecState* exec, JSObject*, JSValue thisValue, const ArgList&)
......
......@@ -32,6 +32,7 @@ namespace JSC {
DatePrototype(ExecState*, PassRefPtr<Structure>);
virtual bool getOwnPropertySlot(ExecState*, const Identifier&, PropertySlot&);
virtual bool getOwnPropertyDescriptor(ExecState*, const Identifier&, PropertyDescriptor&);
virtual const ClassInfo* classInfo() const { return &info; }
static const ClassInfo info;
......
......@@ -241,6 +241,37 @@ bool JSArray::getOwnPropertySlot(ExecState* exec, const Identifier& propertyName
return JSObject::getOwnPropertySlot(exec, propertyName, slot);
}
bool JSArray::getOwnPropertyDescriptor(ExecState* exec, const Identifier& propertyName, PropertyDescriptor& descriptor)
{
if (propertyName == exec->propertyNames().length) {
descriptor.setDescriptor(jsNumber(exec, length()), DontDelete | DontEnum);
return true;
}
bool isArrayIndex;
unsigned i = propertyName.toArrayIndex(&isArrayIndex);
if (isArrayIndex) {
if (i >= m_storage->m_length)
return false;
if (i < m_storage->m_vectorLength) {
JSValue value = m_storage->m_vector[i];
if (value) {
descriptor.setDescriptor(value, 0);
return true;
}
} else if (SparseArrayValueMap* map = m_storage->m_sparseValueMap) {
if (i >= MIN_SPARSE_ARRAY_INDEX) {
SparseArrayValueMap::iterator it = map->find(i);
if (it != map->end()) {
descriptor.setDescriptor(it->second, 0);
return true;
}
}
}
}
return JSObject::getOwnPropertyDescriptor(exec, propertyName, descriptor);
}
// ECMA 15.4.5.1
void JSArray::put(ExecState* exec, const Identifier& propertyName, JSValue value, PutPropertySlot& slot)
{
......
......@@ -47,6 +47,7 @@ namespace JSC {
virtual bool getOwnPropertySlot(ExecState*, const Identifier& propertyName, PropertySlot&);
virtual bool getOwnPropertySlot(ExecState*, unsigned propertyName, PropertySlot&);
virtual bool getOwnPropertyDescriptor(ExecState*, const Identifier&, PropertyDescriptor&);
virtual void put(ExecState*, unsigned propertyName, JSValue); // FIXME: Make protected and add setItem.
static JS_EXPORTDATA const ClassInfo info;
......
......@@ -59,7 +59,18 @@ bool JSByteArray::getOwnPropertySlot(ExecState* exec, const Identifier& property
}
return JSObject::getOwnPropertySlot(exec, propertyName, slot);
}
bool JSByteArray::getOwnPropertyDescriptor(ExecState* exec, const Identifier& propertyName, PropertyDescriptor& descriptor)
{
bool ok;
unsigned index = propertyName.toUInt32(&ok, false);
if (ok && canAccessIndex(index)) {
descriptor.setDescriptor(getIndex(exec, index), DontDelete);
return true;
}
return JSObject::getOwnPropertyDescriptor(exec, propertyName, descriptor);
}
bool JSByteArray::getOwnPropertySlot(ExecState* exec, unsigned propertyName, PropertySlot& slot)
{
if (canAccessIndex(propertyName)) {
......
......@@ -78,6 +78,7 @@ namespace JSC {
virtual bool getOwnPropertySlot(JSC::ExecState*, const JSC::Identifier& propertyName, JSC::PropertySlot&);
virtual bool getOwnPropertySlot(JSC::ExecState*, unsigned propertyName, JSC::PropertySlot&);
virtual bool getOwnPropertyDescriptor(ExecState*, const Identifier&, PropertyDescriptor&);
virtual void put(JSC::ExecState*, const JSC::Identifier& propertyName, JSC::JSValue, JSC::PutPropertySlot&);
virtual void put(JSC::ExecState*, unsigned propertyName, JSC::JSValue);
......
......@@ -177,6 +177,35 @@ bool JSFunction::getOwnPropertySlot(ExecState* exec, const Identifier& propertyN
return Base::getOwnPropertySlot(exec, propertyName, slot);
}
bool JSFunction::getOwnPropertyDescriptor(ExecState* exec, const Identifier& propertyName, PropertyDescriptor& descriptor)
{
if (isHostFunction())
return Base::getOwnPropertyDescriptor(exec, propertyName, descriptor);
if (propertyName == exec->propertyNames().prototype) {
PropertySlot slot;
getOwnPropertySlot(exec, propertyName, slot);
return Base::getOwnPropertyDescriptor(exec, propertyName, descriptor);
}
if (propertyName == exec->propertyNames().arguments) {
descriptor.setDescriptor(exec->interpreter()->retrieveArguments(exec, this), ReadOnly | DontEnum | DontDelete);
return true;
}
if (propertyName == exec->propertyNames().length) {
descriptor.setDescriptor(jsNumber(exec, jsExecutable()->parameterCount()), ReadOnly | DontEnum | DontDelete);
return true;
}
if (propertyName == exec->propertyNames().caller) {
descriptor.setDescriptor(exec->interpreter()->retrieveCaller(exec, this), ReadOnly | DontEnum | DontDelete);
return true;
}
return Base::getOwnPropertyDescriptor(exec, propertyName, descriptor);
}
void JSFunction::put(ExecState* exec, const Identifier& propertyName, JSValue value, PutPropertySlot& slot)
{
if (isHostFunction()) {
......
......@@ -78,6 +78,7 @@ namespace JSC {
bool isHostFunctionNonInline() const;
virtual bool getOwnPropertySlot(ExecState*, const Identifier&, PropertySlot&);
virtual bool getOwnPropertyDescriptor(ExecState*, const Identifier&, PropertyDescriptor&);
virtual void put(ExecState*, const Identifier& propertyName, JSValue, PutPropertySlot&);
virtual bool deleteProperty(ExecState*, const Identifier& propertyName);
......
......@@ -170,6 +170,7 @@ namespace JSC {
virtual void markChildren(MarkStack&);
virtual bool getOwnPropertySlot(ExecState*, const Identifier&, PropertySlot&);
virtual bool getOwnPropertyDescriptor(ExecState*, const Identifier&, PropertyDescriptor&);
virtual bool hasOwnPropertyForWrite(ExecState*, const Identifier&);
virtual void put(ExecState*, const Identifier&, JSValue, PutPropertySlot&);
virtual void putWithAttributes(ExecState*, const Identifier& propertyName, JSValue value, unsigned attributes);
......@@ -326,6 +327,13 @@ namespace JSC {
return symbolTableGet(propertyName, slot);
}
inline bool JSGlobalObject::getOwnPropertyDescriptor(ExecState* exec, const Identifier& propertyName, PropertyDescriptor& descriptor)
{
if (symbolTableGet(propertyName, descriptor))
return true;
return JSVariableObject::getOwnPropertyDescriptor(exec, propertyName, descriptor);
}
inline bool JSGlobalObject::hasOwnPropertyForWrite(ExecState* exec, const Identifier& propertyName)
{
PropertySlot slot;
......
......@@ -93,6 +93,12 @@ bool JSNotAnObject::getOwnPropertySlot(ExecState* exec, unsigned, PropertySlot&)
return false;
}
bool JSNotAnObject::getOwnPropertyDescriptor(ExecState* exec, const Identifier&, PropertyDescriptor&)
{
ASSERT_UNUSED(exec, exec->hadException() && exec->exception() == m_exception);
return false;
}
void JSNotAnObject::put(ExecState* exec, const Identifier& , JSValue, PutPropertySlot&)
{
ASSERT_UNUSED(exec, exec->hadException() && exec->exception() == m_exception);
......
......@@ -80,6 +80,7 @@ namespace JSC {
// JSObject methods
virtual bool getOwnPropertySlot(ExecState*, const Identifier& propertyName, PropertySlot&);
virtual bool getOwnPropertySlot(ExecState*, unsigned propertyName, PropertySlot&);
virtual bool getOwnPropertyDescriptor(ExecState*, const Identifier&, PropertyDescriptor&);
virtual void put(ExecState*, const Identifier& propertyName, JSValue, PutPropertySlot&);
virtual void put(ExecState*, unsigned propertyName, JSValue);
......
......@@ -581,13 +581,12 @@ const ClassInfo JSONObject::info = { "JSON", 0, 0, ExecState::jsonTable };
bool JSONObject::getOwnPropertySlot(ExecState* exec, const Identifier& propertyName, PropertySlot& slot)
{
const HashEntry* entry = ExecState::jsonTable(exec)->entry(exec, propertyName);
if (!entry)
return JSObject::getOwnPropertySlot(exec, propertyName, slot);
return getStaticFunctionSlot<JSObject>(exec, ExecState::jsonTable(exec), this, propertyName, slot);
}
ASSERT(entry->attributes() & Function);
setUpStaticFunctionSlot(exec, entry, this, propertyName, slot);
return true;
bool JSONObject::getOwnPropertyDescriptor(ExecState* exec, const Identifier& propertyName, PropertyDescriptor& descriptor)
{
return getStaticFunctionDescriptor<JSObject>(exec, ExecState::jsonTable(exec), this, propertyName, descriptor);
}
void JSONObject::markStringifiers(MarkStack& markStack, Stringifier* stringifier)
......
......@@ -48,6 +48,7 @@ namespace JSC {
private:
virtual bool getOwnPropertySlot(ExecState*, const Identifier&, PropertySlot&);
virtual bool getOwnPropertyDescriptor(ExecState*, const Identifier&, PropertyDescriptor&);
virtual const ClassInfo* classInfo() const { return &info; }
static const ClassInfo info;
......
......@@ -30,6 +30,7 @@
#include "JSGlobalObject.h"
#include "NativeErrorConstructor.h"
#include "ObjectPrototype.h"
#include "PropertyDescriptor.h"
#include "PropertyNameArray.h"
#include "Lookup.h"
#include "Nodes.h"
......@@ -504,4 +505,27 @@ JSObject* constructEmptyObject(ExecState* exec)
return new (exec) JSObject(exec->lexicalGlobalObject()->emptyObjectStructure());
}
bool JSObject::getOwnPropertyDescriptor(ExecState*, const Identifier& propertyName, PropertyDescriptor& descriptor)
{
unsigned attributes = 0;
JSCell* cell = 0;
size_t offset = m_structure->get(propertyName, attributes, cell);
if (offset == WTF::notFound)
return false;
descriptor.setDescriptor(getDirectOffset(offset), attributes);
return true;
}
bool JSObject::getPropertyDescriptor(ExecState* exec, const Identifier& propertyName, PropertyDescriptor& descriptor)
{
JSObject* object = this;
while (true) {
if (object->getOwnPropertyDescriptor(exec, propertyName, descriptor))
return true;
JSValue prototype = object->prototype();
if (!prototype.isObject())
return false;
object = asObject(prototype);
}
}
} // namespace JSC
......@@ -48,6 +48,7 @@ namespace JSC {
class HashEntry;
class InternalFunction;
class PropertyDescriptor;
class PropertyNameArray;
class Structure;
struct HashTable;
......@@ -95,9 +96,11 @@ namespace JSC {
bool getPropertySlot(ExecState*, const Identifier& propertyName, PropertySlot&);
bool getPropertySlot(ExecState*, unsigned propertyName, PropertySlot&);
bool getPropertyDescriptor(ExecState*, const Identifier& propertyName, PropertyDescriptor&);
virtual bool getOwnPropertySlot(ExecState*, const Identifier& propertyName, PropertySlot&);
virtual bool getOwnPropertySlot(ExecState*, unsigned propertyName, PropertySlot&);
virtual bool getOwnPropertyDescriptor(ExecState*, const Identifier&, PropertyDescriptor&);
virtual void put(ExecState*, const Identifier& propertyName, JSValue value, PutPropertySlot&);
virtual void put(ExecState*, unsigned propertyName, JSValue value);
......
......@@ -103,6 +103,33 @@ bool JSString::getOwnPropertySlot(ExecState* exec, const Identifier& propertyNam
return true;
}
bool JSString::getStringPropertyDescriptor(ExecState* exec, const Identifier& propertyName, PropertyDescriptor& descriptor)
{
if (propertyName == exec->propertyNames().length) {
descriptor.setDescriptor(jsNumber(exec, m_value.size()), DontEnum | DontDelete | ReadOnly);
return true;
}
bool isStrictUInt32;
unsigned i = propertyName.toStrictUInt32(&isStrictUInt32);
if (isStrictUInt32 && i < static_cast<unsigned>(m_value.size())) {
descriptor.setDescriptor(jsSingleCharacterSubstring(exec, m_value, i), DontDelete | ReadOnly);
return true;
}
return false;
}