https://bugs.webkit.org/show_bug.cgi?id=119972
Add attributes field to PropertySlot

Reviewed by Geoff Garen.

For all JSC types, this makes getOwnPropertyDescriptor redundant.
There will be a bit more hacking required in WebCore to remove GOPD whilst maintaining current behaviour.
(Current behaviour is in many ways broken, particularly in that GOPD & GOPS are inconsistent, but we should fix incrementally).

Source/JavaScriptCore: 

No performance impact.

* runtime/PropertySlot.h:
(JSC::PropertySlot::setValue):
(JSC::PropertySlot::setCustom):
(JSC::PropertySlot::setCacheableCustom):
(JSC::PropertySlot::setCustomIndex):
(JSC::PropertySlot::setGetterSlot):
(JSC::PropertySlot::setCacheableGetterSlot):
    - These mathods now all require 'attributes'.
* runtime/JSObject.h:
(JSC::JSObject::getDirect):
(JSC::JSObject::getDirectOffset):
(JSC::JSObject::inlineGetOwnPropertySlot):
    - Added variants of getDirect, getDirectOffset that return the attributes.
* API/JSCallbackObjectFunctions.h:
(JSC::::getOwnPropertySlot):
* runtime/Arguments.cpp:
(JSC::Arguments::getOwnPropertySlotByIndex):
(JSC::Arguments::getOwnPropertySlot):
* runtime/JSActivation.cpp:
(JSC::JSActivation::symbolTableGet):
(JSC::JSActivation::getOwnPropertySlot):
* runtime/JSArray.cpp:
(JSC::JSArray::getOwnPropertySlot):
* runtime/JSArrayBuffer.cpp:
(JSC::JSArrayBuffer::getOwnPropertySlot):
* runtime/JSArrayBufferView.cpp:
(JSC::JSArrayBufferView::getOwnPropertySlot):
* runtime/JSDataView.cpp:
(JSC::JSDataView::getOwnPropertySlot):
* runtime/JSFunction.cpp:
(JSC::JSFunction::getOwnPropertySlot):
* runtime/JSGenericTypedArrayViewInlines.h:
(JSC::::getOwnPropertySlot):
(JSC::::getOwnPropertySlotByIndex):
* runtime/JSObject.cpp:
(JSC::JSObject::getOwnPropertySlotByIndex):
(JSC::JSObject::fillGetterPropertySlot):
* runtime/JSString.h:
(JSC::JSString::getStringPropertySlot):
* runtime/JSSymbolTableObject.h:
(JSC::symbolTableGet):
* runtime/Lookup.cpp:
(JSC::setUpStaticFunctionSlot):
* runtime/Lookup.h:
(JSC::getStaticPropertySlot):
(JSC::getStaticPropertyDescriptor):
(JSC::getStaticValueSlot):
(JSC::getStaticValueDescriptor):
* runtime/RegExpObject.cpp:
(JSC::RegExpObject::getOwnPropertySlot):
* runtime/SparseArrayValueMap.cpp:
(JSC::SparseArrayEntry::get):
    - Pass attributes to PropertySlot::set* methods.

Source/WebCore: 

* bindings/js/JSCSSStyleDeclarationCustom.cpp:
(WebCore::JSCSSStyleDeclaration::getOwnPropertySlotDelegate):
* bindings/js/JSDOMWindowCustom.cpp:
(WebCore::JSDOMWindow::getOwnPropertySlot):
(WebCore::JSDOMWindow::getOwnPropertySlotByIndex):
(WebCore::JSDOMWindow::getOwnPropertyDescriptor):
* bindings/js/JSHistoryCustom.cpp:
(WebCore::JSHistory::getOwnPropertySlotDelegate):
(WebCore::JSHistory::getOwnPropertyDescriptorDelegate):
* bindings/js/JSLocationCustom.cpp:
(WebCore::JSLocation::getOwnPropertySlotDelegate):
(WebCore::JSLocation::getOwnPropertyDescriptorDelegate):
* bindings/js/JSPluginElementFunctions.cpp:
(WebCore::runtimeObjectCustomGetOwnPropertySlot):
(WebCore::runtimeObjectCustomGetOwnPropertyDescriptor):
* bindings/scripts/CodeGeneratorJS.pm:
(GenerateGetOwnPropertySlotBody):
(GenerateGetOwnPropertyDescriptorBody):
(GenerateImplementation):
* bridge/runtime_array.cpp:
(JSC::RuntimeArray::getOwnPropertySlot):
(JSC::RuntimeArray::getOwnPropertyDescriptor):
(JSC::RuntimeArray::getOwnPropertySlotByIndex):
* bridge/runtime_method.cpp:
(JSC::RuntimeMethod::getOwnPropertySlot):
(JSC::RuntimeMethod::getOwnPropertyDescriptor):
* bridge/runtime_object.cpp:
(JSC::Bindings::RuntimeObject::getOwnPropertySlot):
(JSC::Bindings::RuntimeObject::getOwnPropertyDescriptor):
    - Pass attributes to PropertySlot::set* methods.

Source/WebKit2: 

* WebProcess/Plugins/Netscape/JSNPObject.cpp:
(WebKit::JSNPObject::getOwnPropertySlot):
(WebKit::JSNPObject::getOwnPropertyDescriptor):
    - Pass attributes to PropertySlot::set* methods.



git-svn-id: http://svn.webkit.org/repository/webkit/trunk@154253 268f45cc-cd09-0410-ab3c-d52691b4dbfc
diff --git a/Source/JavaScriptCore/API/JSCallbackObjectFunctions.h b/Source/JavaScriptCore/API/JSCallbackObjectFunctions.h
index 834dbe6..460c59a 100644
--- a/Source/JavaScriptCore/API/JSCallbackObjectFunctions.h
+++ b/Source/JavaScriptCore/API/JSCallbackObjectFunctions.h
@@ -137,7 +137,7 @@
                     propertyNameRef = OpaqueJSString::create(name);
                 APICallbackShim callbackShim(exec);
                 if (hasProperty(ctx, thisRef, propertyNameRef.get())) {
-                    slot.setCustom(thisObject, callbackGetter);
+                    slot.setCustom(thisObject, ReadOnly | DontEnum, callbackGetter);
                     return true;
                 }
             } else if (JSObjectGetPropertyCallback getProperty = jsClass->getProperty) {
@@ -151,11 +151,11 @@
                 }
                 if (exception) {
                     throwError(exec, toJS(exec, exception));
-                    slot.setValue(thisObject, jsUndefined());
+                    slot.setValue(thisObject, ReadOnly | DontEnum, jsUndefined());
                     return true;
                 }
                 if (value) {
-                    slot.setValue(thisObject, toJS(exec, value));
+                    slot.setValue(thisObject, ReadOnly | DontEnum, toJS(exec, value));
                     return true;
                 }
             }
@@ -164,7 +164,7 @@
                 if (staticValues->contains(name)) {
                     JSValue value = thisObject->getStaticValue(exec, propertyName);
                     if (value) {
-                        slot.setValue(thisObject, value);
+                        slot.setValue(thisObject, ReadOnly | DontEnum, value);
                         return true;
                     }
                 }
@@ -172,7 +172,7 @@
             
             if (OpaqueJSClassStaticFunctionsTable* staticFunctions = jsClass->staticFunctions(exec)) {
                 if (staticFunctions->contains(name)) {
-                    slot.setCustom(thisObject, staticFunctionGetter);
+                    slot.setCustom(thisObject, ReadOnly | DontEnum, staticFunctionGetter);
                     return true;
                 }
             }
diff --git a/Source/JavaScriptCore/ChangeLog b/Source/JavaScriptCore/ChangeLog
index 4bf0897..47fbbe0 100644
--- a/Source/JavaScriptCore/ChangeLog
+++ b/Source/JavaScriptCore/ChangeLog
@@ -1,3 +1,70 @@
+2013-08-18  Gavin Barraclough  <barraclough@apple.com>
+
+        https://bugs.webkit.org/show_bug.cgi?id=119972
+        Add attributes field to PropertySlot
+
+        Reviewed by Geoff Garen.
+
+        For all JSC types, this makes getOwnPropertyDescriptor redundant.
+        There will be a bit more hacking required in WebCore to remove GOPD whilst maintaining current behaviour.
+        (Current behaviour is in many ways broken, particularly in that GOPD & GOPS are inconsistent, but we should fix incrementally).
+
+        No performance impact.
+
+        * runtime/PropertySlot.h:
+        (JSC::PropertySlot::setValue):
+        (JSC::PropertySlot::setCustom):
+        (JSC::PropertySlot::setCacheableCustom):
+        (JSC::PropertySlot::setCustomIndex):
+        (JSC::PropertySlot::setGetterSlot):
+        (JSC::PropertySlot::setCacheableGetterSlot):
+            - These mathods now all require 'attributes'.
+        * runtime/JSObject.h:
+        (JSC::JSObject::getDirect):
+        (JSC::JSObject::getDirectOffset):
+        (JSC::JSObject::inlineGetOwnPropertySlot):
+            - Added variants of getDirect, getDirectOffset that return the attributes.
+        * API/JSCallbackObjectFunctions.h:
+        (JSC::::getOwnPropertySlot):
+        * runtime/Arguments.cpp:
+        (JSC::Arguments::getOwnPropertySlotByIndex):
+        (JSC::Arguments::getOwnPropertySlot):
+        * runtime/JSActivation.cpp:
+        (JSC::JSActivation::symbolTableGet):
+        (JSC::JSActivation::getOwnPropertySlot):
+        * runtime/JSArray.cpp:
+        (JSC::JSArray::getOwnPropertySlot):
+        * runtime/JSArrayBuffer.cpp:
+        (JSC::JSArrayBuffer::getOwnPropertySlot):
+        * runtime/JSArrayBufferView.cpp:
+        (JSC::JSArrayBufferView::getOwnPropertySlot):
+        * runtime/JSDataView.cpp:
+        (JSC::JSDataView::getOwnPropertySlot):
+        * runtime/JSFunction.cpp:
+        (JSC::JSFunction::getOwnPropertySlot):
+        * runtime/JSGenericTypedArrayViewInlines.h:
+        (JSC::::getOwnPropertySlot):
+        (JSC::::getOwnPropertySlotByIndex):
+        * runtime/JSObject.cpp:
+        (JSC::JSObject::getOwnPropertySlotByIndex):
+        (JSC::JSObject::fillGetterPropertySlot):
+        * runtime/JSString.h:
+        (JSC::JSString::getStringPropertySlot):
+        * runtime/JSSymbolTableObject.h:
+        (JSC::symbolTableGet):
+        * runtime/Lookup.cpp:
+        (JSC::setUpStaticFunctionSlot):
+        * runtime/Lookup.h:
+        (JSC::getStaticPropertySlot):
+        (JSC::getStaticPropertyDescriptor):
+        (JSC::getStaticValueSlot):
+        (JSC::getStaticValueDescriptor):
+        * runtime/RegExpObject.cpp:
+        (JSC::RegExpObject::getOwnPropertySlot):
+        * runtime/SparseArrayValueMap.cpp:
+        (JSC::SparseArrayEntry::get):
+            - Pass attributes to PropertySlot::set* methods.
+
 2013-08-17  Mark Hahnenberg  <mhahnenberg@apple.com>
 
         <https://webkit.org/b/119919> Concurrent JIT crashes in various fast/js/dfg-* tests while the main thread is setting innerHTML
diff --git a/Source/JavaScriptCore/runtime/Arguments.cpp b/Source/JavaScriptCore/runtime/Arguments.cpp
index 5851106..6547375 100644
--- a/Source/JavaScriptCore/runtime/Arguments.cpp
+++ b/Source/JavaScriptCore/runtime/Arguments.cpp
@@ -94,7 +94,7 @@
 {
     Arguments* thisObject = jsCast<Arguments*>(object);
     if (JSValue value = thisObject->tryGetArgument(i)) {
-        slot.setValue(thisObject, value);
+        slot.setValue(thisObject, None, value);
         return true;
     }
 
@@ -129,18 +129,18 @@
     unsigned i = propertyName.asIndex();
     if (JSValue value = thisObject->tryGetArgument(i)) {
         RELEASE_ASSERT(i < PropertyName::NotAnIndex);
-        slot.setValue(thisObject, value);
+        slot.setValue(thisObject, None, value);
         return true;
     }
 
     if (propertyName == exec->propertyNames().length && LIKELY(!thisObject->m_overrodeLength)) {
-        slot.setValue(thisObject, jsNumber(thisObject->m_numArguments));
+        slot.setValue(thisObject, DontEnum, jsNumber(thisObject->m_numArguments));
         return true;
     }
 
     if (propertyName == exec->propertyNames().callee && LIKELY(!thisObject->m_overrodeCallee)) {
         if (!thisObject->m_isStrictMode) {
-            slot.setValue(thisObject, thisObject->m_callee.get());
+            slot.setValue(thisObject, DontEnum, thisObject->m_callee.get());
             return true;
         }
         thisObject->createStrictModeCalleeIfNecessary(exec);
diff --git a/Source/JavaScriptCore/runtime/JSActivation.cpp b/Source/JavaScriptCore/runtime/JSActivation.cpp
index bc2fe03..9855fb6 100644
--- a/Source/JavaScriptCore/runtime/JSActivation.cpp
+++ b/Source/JavaScriptCore/runtime/JSActivation.cpp
@@ -66,7 +66,7 @@
     if (isTornOff() && !isValid(entry))
         return false;
 
-    slot.setValue(this, registerAt(entry.getIndex()).get());
+    slot.setValue(this, DontEnum, registerAt(entry.getIndex()).get());
     return true;
 }
 
@@ -157,7 +157,7 @@
     if (propertyName == exec->propertyNames().arguments) {
         // Defend against the inspector asking for the arguments object after it has been optimized out.
         if (!thisObject->isTornOff()) {
-            slot.setCustom(thisObject, thisObject->getArgumentsGetter());
+            slot.setCustom(thisObject, DontEnum, thisObject->getArgumentsGetter());
             return true;
         }
     }
@@ -165,8 +165,9 @@
     if (thisObject->symbolTableGet(propertyName, slot))
         return true;
 
-    if (JSValue value = thisObject->getDirect(exec->vm(), propertyName)) {
-        slot.setValue(thisObject, value);
+    unsigned attributes;
+    if (JSValue value = thisObject->getDirect(exec->vm(), propertyName, attributes)) {
+        slot.setValue(thisObject, attributes, value);
         return true;
     }
 
diff --git a/Source/JavaScriptCore/runtime/JSArray.cpp b/Source/JavaScriptCore/runtime/JSArray.cpp
index 35d6ca3..5f57e37 100644
--- a/Source/JavaScriptCore/runtime/JSArray.cpp
+++ b/Source/JavaScriptCore/runtime/JSArray.cpp
@@ -181,7 +181,8 @@
 {
     JSArray* thisObject = jsCast<JSArray*>(object);
     if (propertyName == exec->propertyNames().length) {
-        slot.setValue(thisObject, jsNumber(thisObject->length()));
+        unsigned attributes = thisObject->isLengthWritable() ? DontDelete | DontEnum : DontDelete | DontEnum | ReadOnly;
+        slot.setValue(thisObject, attributes, jsNumber(thisObject->length()));
         return true;
     }
 
diff --git a/Source/JavaScriptCore/runtime/JSArrayBuffer.cpp b/Source/JavaScriptCore/runtime/JSArrayBuffer.cpp
index a89af56..622fa35 100644
--- a/Source/JavaScriptCore/runtime/JSArrayBuffer.cpp
+++ b/Source/JavaScriptCore/runtime/JSArrayBuffer.cpp
@@ -71,7 +71,7 @@
     JSArrayBuffer* thisObject = jsCast<JSArrayBuffer*>(object);
     
     if (propertyName == exec->propertyNames().byteLength) {
-        slot.setValue(thisObject, jsNumber(thisObject->impl()->byteLength()));
+        slot.setValue(thisObject, DontDelete | ReadOnly, jsNumber(thisObject->impl()->byteLength()));
         return true;
     }
     
diff --git a/Source/JavaScriptCore/runtime/JSArrayBufferView.cpp b/Source/JavaScriptCore/runtime/JSArrayBufferView.cpp
index be039c3..a07f403 100644
--- a/Source/JavaScriptCore/runtime/JSArrayBufferView.cpp
+++ b/Source/JavaScriptCore/runtime/JSArrayBufferView.cpp
@@ -125,13 +125,13 @@
 {
     JSArrayBufferView* thisObject = jsCast<JSArrayBufferView*>(object);
     if (propertyName == exec->propertyNames().byteOffset) {
-        slot.setValue(thisObject, jsNumber(thisObject->byteOffset()));
+        slot.setValue(thisObject, DontDelete | ReadOnly, jsNumber(thisObject->byteOffset()));
         return true;
     }
     
     if (propertyName == exec->propertyNames().buffer) {
         slot.setValue(
-            thisObject, exec->vm().m_typedArrayController->toJS(
+            thisObject, DontDelete | ReadOnly, exec->vm().m_typedArrayController->toJS(
                 exec, thisObject->globalObject(), thisObject->buffer()));
         return true;
     }
diff --git a/Source/JavaScriptCore/runtime/JSDataView.cpp b/Source/JavaScriptCore/runtime/JSDataView.cpp
index 1289ff2..92856f7 100644
--- a/Source/JavaScriptCore/runtime/JSDataView.cpp
+++ b/Source/JavaScriptCore/runtime/JSDataView.cpp
@@ -88,7 +88,7 @@
 {
     JSDataView* thisObject = jsCast<JSDataView*>(object);
     if (propertyName == exec->propertyNames().byteLength) {
-        slot.setValue(thisObject, jsNumber(thisObject->m_length));
+        slot.setValue(thisObject, DontEnum | ReadOnly, jsNumber(thisObject->m_length));
         return true;
     }
     
diff --git a/Source/JavaScriptCore/runtime/JSFunction.cpp b/Source/JavaScriptCore/runtime/JSFunction.cpp
index bfd45a3..1106fc5 100644
--- a/Source/JavaScriptCore/runtime/JSFunction.cpp
+++ b/Source/JavaScriptCore/runtime/JSFunction.cpp
@@ -248,16 +248,17 @@
 
     if (propertyName == exec->propertyNames().prototype) {
         VM& vm = exec->vm();
-        PropertyOffset offset = thisObject->getDirectOffset(vm, propertyName);
+        unsigned attributes;
+        PropertyOffset offset = thisObject->getDirectOffset(vm, propertyName, attributes);
         if (!isValidOffset(offset)) {
             JSObject* prototype = constructEmptyObject(exec);
             prototype->putDirect(vm, exec->propertyNames().constructor, thisObject, DontEnum);
             thisObject->putDirect(vm, exec->propertyNames().prototype, prototype, DontDelete | DontEnum);
-            offset = thisObject->getDirectOffset(vm, exec->propertyNames().prototype);
+            offset = thisObject->getDirectOffset(vm, exec->propertyNames().prototype, attributes);
             ASSERT(isValidOffset(offset));
         }
 
-        slot.setValue(thisObject, thisObject->getDirect(offset), offset);
+        slot.setValue(thisObject, attributes, thisObject->getDirect(offset), offset);
     }
 
     if (propertyName == exec->propertyNames().arguments) {
@@ -270,17 +271,17 @@
             }
             return result;
         }
-        slot.setCacheableCustom(thisObject, argumentsGetter);
+        slot.setCacheableCustom(thisObject, ReadOnly | DontEnum | DontDelete, argumentsGetter);
         return true;
     }
 
     if (propertyName == exec->propertyNames().length) {
-        slot.setCacheableCustom(thisObject, lengthGetter);
+        slot.setCacheableCustom(thisObject, ReadOnly | DontEnum | DontDelete, lengthGetter);
         return true;
     }
 
     if (propertyName == exec->propertyNames().name) {
-        slot.setCacheableCustom(thisObject, nameGetter);
+        slot.setCacheableCustom(thisObject, ReadOnly | DontEnum | DontDelete, nameGetter);
         return true;
     }
 
@@ -294,7 +295,7 @@
             }
             return result;
         }
-        slot.setCacheableCustom(thisObject, callerGetter);
+        slot.setCacheableCustom(thisObject, ReadOnly | DontEnum | DontDelete, callerGetter);
         return true;
     }
 
diff --git a/Source/JavaScriptCore/runtime/JSGenericTypedArrayViewInlines.h b/Source/JavaScriptCore/runtime/JSGenericTypedArrayViewInlines.h
index 98f6f90..1037bec 100644
--- a/Source/JavaScriptCore/runtime/JSGenericTypedArrayViewInlines.h
+++ b/Source/JavaScriptCore/runtime/JSGenericTypedArrayViewInlines.h
@@ -215,18 +215,18 @@
 {
     JSGenericTypedArrayView* thisObject = jsCast<JSGenericTypedArrayView*>(object);
     if (propertyName == exec->propertyNames().length) {
-        slot.setValue(thisObject, jsNumber(thisObject->length()));
+        slot.setValue(thisObject, DontDelete | ReadOnly, jsNumber(thisObject->length()));
         return true;
     }
     
     if (propertyName == exec->propertyNames().byteLength) {
-        slot.setValue(thisObject, jsNumber(thisObject->byteLength()));
+        slot.setValue(thisObject, DontDelete | ReadOnly, jsNumber(thisObject->byteLength()));
         return true;
     }
     
     unsigned index = propertyName.asIndex();
     if (index != PropertyName::NotAnIndex && thisObject->canGetIndexQuickly(index)) {
-        slot.setValue(thisObject, thisObject->getIndexQuickly(index));
+        slot.setValue(thisObject, DontDelete | ReadOnly, thisObject->getIndexQuickly(index));
         return true;
     }
     
@@ -324,7 +324,7 @@
     if (!thisObject->canGetIndexQuickly(propertyName))
         return false;
     
-    slot.setValue(thisObject, thisObject->getIndexQuickly(propertyName));
+    slot.setValue(thisObject, None, thisObject->getIndexQuickly(propertyName));
     return true;
 }
 
diff --git a/Source/JavaScriptCore/runtime/JSObject.cpp b/Source/JavaScriptCore/runtime/JSObject.cpp
index 2eec645..593e89e 100644
--- a/Source/JavaScriptCore/runtime/JSObject.cpp
+++ b/Source/JavaScriptCore/runtime/JSObject.cpp
@@ -289,7 +289,7 @@
         
         JSValue value = butterfly->contiguous()[i].get();
         if (value) {
-            slot.setValue(thisObject, value);
+            slot.setValue(thisObject, None, value);
             return true;
         }
         
@@ -303,7 +303,7 @@
         
         double value = butterfly->contiguousDouble()[i];
         if (value == value) {
-            slot.setValue(thisObject, JSValue(JSValue::EncodeAsDouble, value));
+            slot.setValue(thisObject, None, JSValue(JSValue::EncodeAsDouble, value));
             return true;
         }
         
@@ -318,7 +318,7 @@
         if (i < storage->vectorLength()) {
             JSValue value = storage->m_vector[i].get();
             if (value) {
-                slot.setValue(thisObject, value);
+                slot.setValue(thisObject, None, value);
                 return true;
             }
         } else if (SparseArrayValueMap* map = storage->m_sparseMap.get()) {
@@ -1625,14 +1625,14 @@
     return true;
 }
 
-NEVER_INLINE void JSObject::fillGetterPropertySlot(PropertySlot& slot, JSValue getterSetter, PropertyOffset offset)
+NEVER_INLINE void JSObject::fillGetterPropertySlot(PropertySlot& slot, JSValue getterSetter, unsigned attributes, PropertyOffset offset)
 {
     if (structure()->isDictionary()) {
-        slot.setGetterSlot(this, jsCast<GetterSetter*>(getterSetter));
+        slot.setGetterSlot(this, attributes, jsCast<GetterSetter*>(getterSetter));
         return;
     }
 
-    slot.setCacheableGetterSlot(this, jsCast<GetterSetter*>(getterSetter), offset);
+    slot.setCacheableGetterSlot(this, attributes, jsCast<GetterSetter*>(getterSetter), offset);
 }
 
 void JSObject::putIndexedDescriptor(ExecState* exec, SparseArrayEntry* entryInMap, PropertyDescriptor& descriptor, PropertyDescriptor& oldDescriptor)
diff --git a/Source/JavaScriptCore/runtime/JSObject.h b/Source/JavaScriptCore/runtime/JSObject.h
index 61753f8..0db70e3 100644
--- a/Source/JavaScriptCore/runtime/JSObject.h
+++ b/Source/JavaScriptCore/runtime/JSObject.h
@@ -73,17 +73,6 @@
 JS_EXPORT_PRIVATE JSObject* throwTypeError(ExecState*, const String&);
 extern JS_EXPORTDATA const char* StrictModeReadonlyPropertyWriteError;
 
-// ECMA 262-3 8.6.1
-// Property attributes
-enum Attribute {
-    None         = 0,
-    ReadOnly     = 1 << 1,  // property can be only read, not written
-    DontEnum     = 1 << 2,  // property doesn't appear in (for .. in ..)
-    DontDelete   = 1 << 3,  // property can't be deleted
-    Function     = 1 << 4,  // property is a function - only used by static hashtables
-    Accessor     = 1 << 5,  // property is a getter/setter
-};
-
 COMPILE_ASSERT(None < FirstInternalAttribute, None_is_below_FirstInternalAttribute);
 COMPILE_ASSERT(ReadOnly < FirstInternalAttribute, ReadOnly_is_below_FirstInternalAttribute);
 COMPILE_ASSERT(DontEnum < FirstInternalAttribute, DontEnum_is_below_FirstInternalAttribute);
@@ -510,6 +499,14 @@
         return offset != invalidOffset ? getDirect(offset) : JSValue();
     }
 
+    JSValue getDirect(VM& vm, PropertyName propertyName, unsigned& attributes) const
+    {
+        JSCell* specific;
+        PropertyOffset offset = structure()->get(vm, propertyName, attributes, specific);
+        checkOffset(offset, structure()->inlineCapacity());
+        return offset != invalidOffset ? getDirect(offset) : JSValue();
+    }
+
     PropertyOffset getDirectOffset(VM& vm, PropertyName propertyName)
     {
         PropertyOffset offset = structure()->get(vm, propertyName);
@@ -517,6 +514,14 @@
         return offset;
     }
 
+    PropertyOffset getDirectOffset(VM& vm, PropertyName propertyName, unsigned& attributes)
+    {
+        JSCell* specific;
+        PropertyOffset offset = structure()->get(vm, propertyName, attributes, specific);
+        checkOffset(offset, structure()->inlineCapacity());
+        return offset;
+    }
+
     bool hasInlineStorage() const { return structure()->hasInlineStorage(); }
     ConstPropertyStorage inlineStorageUnsafe() const
     {
@@ -936,7 +941,7 @@
     bool putDirectInternal(VM&, PropertyName, JSValue, unsigned attr, PutPropertySlot&, JSCell*);
 
     bool inlineGetOwnPropertySlot(ExecState*, PropertyName, PropertySlot&);
-    JS_EXPORT_PRIVATE void fillGetterPropertySlot(PropertySlot&, JSValue, PropertyOffset);
+    JS_EXPORT_PRIVATE void fillGetterPropertySlot(PropertySlot&, JSValue, unsigned, PropertyOffset);
 
     const HashEntry* findPropertyHashEntry(ExecState*, PropertyName) const;
         
@@ -1168,13 +1173,15 @@
 
 ALWAYS_INLINE bool JSObject::inlineGetOwnPropertySlot(ExecState* exec, PropertyName propertyName, PropertySlot& slot)
 {
-    PropertyOffset offset = structure()->get(exec->vm(), propertyName);
+    unsigned attributes;
+    JSCell* specific;
+    PropertyOffset offset = structure()->get(exec->vm(), propertyName, attributes, specific);
     if (LIKELY(isValidOffset(offset))) {
         JSValue value = getDirect(offset);
         if (structure()->hasGetterSetterProperties() && value.isGetterSetter())
-            fillGetterPropertySlot(slot, value, offset);
+            fillGetterPropertySlot(slot, value, attributes, offset);
         else
-            slot.setValue(this, value, offset);
+            slot.setValue(this, attributes, value, offset);
         return true;
     }
 
diff --git a/Source/JavaScriptCore/runtime/JSString.h b/Source/JavaScriptCore/runtime/JSString.h
index e1bce7f..644c50c 100644
--- a/Source/JavaScriptCore/runtime/JSString.h
+++ b/Source/JavaScriptCore/runtime/JSString.h
@@ -473,14 +473,14 @@
     ALWAYS_INLINE bool JSString::getStringPropertySlot(ExecState* exec, PropertyName propertyName, PropertySlot& slot)
     {
         if (propertyName == exec->propertyNames().length) {
-            slot.setValue(this, jsNumber(m_length));
+            slot.setValue(this, DontEnum | DontDelete | ReadOnly, jsNumber(m_length));
             return true;
         }
 
         unsigned i = propertyName.asIndex();
         if (i < m_length) {
             ASSERT(i != PropertyName::NotAnIndex); // No need for an explicit check, the above test would always fail!
-            slot.setValue(this, getIndex(exec, i));
+            slot.setValue(this, DontDelete | ReadOnly, getIndex(exec, i));
             return true;
         }
 
@@ -490,7 +490,7 @@
     ALWAYS_INLINE bool JSString::getStringPropertySlot(ExecState* exec, unsigned propertyName, PropertySlot& slot)
     {
         if (propertyName < m_length) {
-            slot.setValue(this, getIndex(exec, propertyName));
+            slot.setValue(this, DontDelete | ReadOnly, getIndex(exec, propertyName));
             return true;
         }
 
diff --git a/Source/JavaScriptCore/runtime/JSSymbolTableObject.h b/Source/JavaScriptCore/runtime/JSSymbolTableObject.h
index ecbeffe..c8ff36b 100644
--- a/Source/JavaScriptCore/runtime/JSSymbolTableObject.h
+++ b/Source/JavaScriptCore/runtime/JSSymbolTableObject.h
@@ -79,7 +79,7 @@
         return false;
     SymbolTableEntry::Fast entry = iter->value;
     ASSERT(!entry.isNull());
-    slot.setValue(object, object->registerAt(entry.getIndex()).get());
+    slot.setValue(object, entry.getAttributes(), object->registerAt(entry.getIndex()).get());
     return true;
 }
 
@@ -111,7 +111,7 @@
         return false;
     SymbolTableEntry::Fast entry = iter->value;
     ASSERT(!entry.isNull());
-    slot.setValue(object, object->registerAt(entry.getIndex()).get());
+    slot.setValue(object, entry.getAttributes(), object->registerAt(entry.getIndex()).get());
     slotIsWriteable = !entry.isReadOnly();
     return true;
 }
diff --git a/Source/JavaScriptCore/runtime/Lookup.cpp b/Source/JavaScriptCore/runtime/Lookup.cpp
index 030aef5..7d8d232 100644
--- a/Source/JavaScriptCore/runtime/Lookup.cpp
+++ b/Source/JavaScriptCore/runtime/Lookup.cpp
@@ -69,7 +69,8 @@
 {
     ASSERT(thisObj->globalObject());
     ASSERT(entry->attributes() & Function);
-    PropertyOffset offset = thisObj->getDirectOffset(exec->vm(), propertyName);
+    unsigned attributes;
+    PropertyOffset offset = thisObj->getDirectOffset(exec->vm(), propertyName, attributes);
 
     if (!isValidOffset(offset)) {
         // If a property is ever deleted from an object with a static table, then we reify
@@ -80,11 +81,11 @@
         thisObj->putDirectNativeFunction(
             exec, thisObj->globalObject(), propertyName, entry->functionLength(),
             entry->function(), entry->intrinsic(), entry->attributes());
-        offset = thisObj->getDirectOffset(exec->vm(), propertyName);
+        offset = thisObj->getDirectOffset(exec->vm(), propertyName, attributes);
         ASSERT(isValidOffset(offset));
     }
 
-    slot.setValue(thisObj, thisObj->getDirect(offset), offset);
+    slot.setValue(thisObj, attributes, thisObj->getDirect(offset), offset);
     return true;
 }
 
diff --git a/Source/JavaScriptCore/runtime/Lookup.h b/Source/JavaScriptCore/runtime/Lookup.h
index c7d4283..c3ff8bf 100644
--- a/Source/JavaScriptCore/runtime/Lookup.h
+++ b/Source/JavaScriptCore/runtime/Lookup.h
@@ -251,7 +251,7 @@
         if (entry->attributes() & Function)
             return setUpStaticFunctionSlot(exec, entry, thisObj, propertyName, slot);
 
-        slot.setCacheableCustom(thisObj, entry->propertyGetter());
+        slot.setCacheableCustom(thisObj, entry->attributes(), entry->propertyGetter());
         return true;
     }
 
@@ -271,7 +271,7 @@
             return present;
         }
 
-        slot.setCustom(thisObj, entry->propertyGetter());
+        slot.setCustom(thisObj, entry->attributes(), entry->propertyGetter());
         descriptor.setDescriptor(slot.getValue(exec, propertyName), entry->attributes());
         return true;
     }
@@ -330,7 +330,7 @@
 
         ASSERT(!(entry->attributes() & Function));
 
-        slot.setCacheableCustom(thisObj, entry->propertyGetter());
+        slot.setCacheableCustom(thisObj, entry->attributes(), entry->propertyGetter());
         return true;
     }
 
@@ -348,7 +348,7 @@
         
         ASSERT(!(entry->attributes() & Function));
         PropertySlot slot(thisObj);
-        slot.setCustom(thisObj, entry->propertyGetter());
+        slot.setCustom(thisObj, entry->attributes(), entry->propertyGetter());
         descriptor.setDescriptor(slot.getValue(exec, propertyName), entry->attributes());
         return true;
     }
diff --git a/Source/JavaScriptCore/runtime/PropertySlot.h b/Source/JavaScriptCore/runtime/PropertySlot.h
index 8f74173..78714b7 100644
--- a/Source/JavaScriptCore/runtime/PropertySlot.h
+++ b/Source/JavaScriptCore/runtime/PropertySlot.h
@@ -33,6 +33,17 @@
 class ExecState;
 class GetterSetter;
 
+// ECMA 262-3 8.6.1
+// Property attributes
+enum Attribute {
+    None         = 0,
+    ReadOnly     = 1 << 1,  // property can be only read, not written
+    DontEnum     = 1 << 2,  // property doesn't appear in (for .. in ..)
+    DontDelete   = 1 << 3,  // property can't be deleted
+    Function     = 1 << 4,  // property is a function - only used by static hashtables
+    Accessor     = 1 << 5,  // property is a getter/setter
+};
+
 class PropertySlot {
     enum PropertyType {
         TypeUnset,
@@ -79,10 +90,11 @@
         return m_slotBase;
     }
 
-    void setValue(JSObject* slotBase, JSValue value)
+    void setValue(JSObject* slotBase, unsigned attributes, JSValue value)
     {
         ASSERT(value);
         m_data.value = JSValue::encode(value);
+        m_attributes = attributes;
 
         ASSERT(slotBase);
         m_slotBase = slotBase;
@@ -90,10 +102,11 @@
         m_offset = invalidOffset;
     }
     
-    void setValue(JSObject* slotBase, JSValue value, PropertyOffset offset)
+    void setValue(JSObject* slotBase, unsigned attributes, JSValue value, PropertyOffset offset)
     {
         ASSERT(value);
         m_data.value = JSValue::encode(value);
+        m_attributes = attributes;
 
         ASSERT(slotBase);
         m_slotBase = slotBase;
@@ -101,20 +114,22 @@
         m_offset = offset;
     }
 
-    void setValue(JSString*, JSValue value)
+    void setValue(JSString*, unsigned attributes, JSValue value)
     {
         ASSERT(value);
         m_data.value = JSValue::encode(value);
+        m_attributes = attributes;
 
         m_slotBase = 0;
         m_propertyType = TypeValue;
         m_offset = invalidOffset;
     }
 
-    void setCustom(JSObject* slotBase, GetValueFunc getValue)
+    void setCustom(JSObject* slotBase, unsigned attributes, GetValueFunc getValue)
     {
         ASSERT(getValue);
         m_data.custom.getValue = getValue;
+        m_attributes = attributes;
 
         ASSERT(slotBase);
         m_slotBase = slotBase;
@@ -122,10 +137,11 @@
         m_offset = invalidOffset;
     }
     
-    void setCacheableCustom(JSObject* slotBase, GetValueFunc getValue)
+    void setCacheableCustom(JSObject* slotBase, unsigned attributes, GetValueFunc getValue)
     {
         ASSERT(getValue);
         m_data.custom.getValue = getValue;
+        m_attributes = attributes;
 
         ASSERT(slotBase);
         m_slotBase = slotBase;
@@ -133,11 +149,12 @@
         m_offset = !invalidOffset;
     }
 
-    void setCustomIndex(JSObject* slotBase, unsigned index, GetIndexValueFunc getIndexValue)
+    void setCustomIndex(JSObject* slotBase, unsigned attributes, unsigned index, GetIndexValueFunc getIndexValue)
     {
         ASSERT(getIndexValue);
         m_data.customIndex.getIndexValue = getIndexValue;
         m_data.customIndex.index = index;
+        m_attributes = attributes;
 
         ASSERT(slotBase);
         m_slotBase = slotBase;
@@ -145,10 +162,11 @@
         m_offset = invalidOffset;
     }
 
-    void setGetterSlot(JSObject* slotBase, GetterSetter* getterSetter)
+    void setGetterSlot(JSObject* slotBase, unsigned attributes, GetterSetter* getterSetter)
     {
         ASSERT(getterSetter);
         m_data.getter.getterSetter = getterSetter;
+        m_attributes = attributes;
 
         ASSERT(slotBase);
         m_slotBase = slotBase;
@@ -156,10 +174,11 @@
         m_offset = invalidOffset;
     }
 
-    void setCacheableGetterSlot(JSObject* slotBase, GetterSetter* getterSetter, PropertyOffset offset)
+    void setCacheableGetterSlot(JSObject* slotBase, unsigned attributes, GetterSetter* getterSetter, PropertyOffset offset)
     {
         ASSERT(getterSetter);
         m_data.getter.getterSetter = getterSetter;
+        m_attributes = attributes;
 
         ASSERT(slotBase);
         m_slotBase = slotBase;
@@ -179,6 +198,7 @@
 private:
     JS_EXPORT_PRIVATE JSValue functionGetter(ExecState*) const;
 
+    unsigned m_attributes;
     union {
         EncodedJSValue value;
         struct {
diff --git a/Source/JavaScriptCore/runtime/RegExpObject.cpp b/Source/JavaScriptCore/runtime/RegExpObject.cpp
index 5e7856f..7ab1adb 100644
--- a/Source/JavaScriptCore/runtime/RegExpObject.cpp
+++ b/Source/JavaScriptCore/runtime/RegExpObject.cpp
@@ -93,7 +93,8 @@
 {
     if (propertyName == exec->propertyNames().lastIndex) {
         RegExpObject* regExp = asRegExpObject(object);
-        slot.setValue(regExp, regExp->getLastIndex());
+        unsigned attributes = regExp->m_lastIndexIsWritable ? DontDelete | DontEnum : DontDelete | DontEnum | ReadOnly;
+        slot.setValue(regExp, attributes, regExp->getLastIndex());
         return true;
     }
     return getStaticValueSlot<RegExpObject, JSObject>(exec, ExecState::regExpTable(exec), jsCast<RegExpObject*>(object), propertyName, slot);
diff --git a/Source/JavaScriptCore/runtime/SparseArrayValueMap.cpp b/Source/JavaScriptCore/runtime/SparseArrayValueMap.cpp
index f739d29..0db43b7 100644
--- a/Source/JavaScriptCore/runtime/SparseArrayValueMap.cpp
+++ b/Source/JavaScriptCore/runtime/SparseArrayValueMap.cpp
@@ -128,11 +128,11 @@
     ASSERT(value);
 
     if (LIKELY(!value.isGetterSetter())) {
-        slot.setValue(thisObject, value);
+        slot.setValue(thisObject, attributes, value);
         return;
     }
 
-    slot.setGetterSlot(thisObject, jsCast<GetterSetter*>(value));
+    slot.setGetterSlot(thisObject, attributes, jsCast<GetterSetter*>(value));
 }
 
 void SparseArrayEntry::get(PropertyDescriptor& descriptor) const
diff --git a/Source/WebCore/ChangeLog b/Source/WebCore/ChangeLog
index 64cc7a6..58a00b9b 100644
--- a/Source/WebCore/ChangeLog
+++ b/Source/WebCore/ChangeLog
@@ -1,3 +1,45 @@
+2013-08-18  Gavin Barraclough  <barraclough@apple.com>
+
+        https://bugs.webkit.org/show_bug.cgi?id=119972
+        Add attributes field to PropertySlot
+
+        Reviewed by Geoff Garen.
+
+        For all JSC types, this makes getOwnPropertyDescriptor redundant.
+        There will be a bit more hacking required in WebCore to remove GOPD whilst maintaining current behaviour.
+        (Current behaviour is in many ways broken, particularly in that GOPD & GOPS are inconsistent, but we should fix incrementally).
+
+        * bindings/js/JSCSSStyleDeclarationCustom.cpp:
+        (WebCore::JSCSSStyleDeclaration::getOwnPropertySlotDelegate):
+        * bindings/js/JSDOMWindowCustom.cpp:
+        (WebCore::JSDOMWindow::getOwnPropertySlot):
+        (WebCore::JSDOMWindow::getOwnPropertySlotByIndex):
+        (WebCore::JSDOMWindow::getOwnPropertyDescriptor):
+        * bindings/js/JSHistoryCustom.cpp:
+        (WebCore::JSHistory::getOwnPropertySlotDelegate):
+        (WebCore::JSHistory::getOwnPropertyDescriptorDelegate):
+        * bindings/js/JSLocationCustom.cpp:
+        (WebCore::JSLocation::getOwnPropertySlotDelegate):
+        (WebCore::JSLocation::getOwnPropertyDescriptorDelegate):
+        * bindings/js/JSPluginElementFunctions.cpp:
+        (WebCore::runtimeObjectCustomGetOwnPropertySlot):
+        (WebCore::runtimeObjectCustomGetOwnPropertyDescriptor):
+        * bindings/scripts/CodeGeneratorJS.pm:
+        (GenerateGetOwnPropertySlotBody):
+        (GenerateGetOwnPropertyDescriptorBody):
+        (GenerateImplementation):
+        * bridge/runtime_array.cpp:
+        (JSC::RuntimeArray::getOwnPropertySlot):
+        (JSC::RuntimeArray::getOwnPropertyDescriptor):
+        (JSC::RuntimeArray::getOwnPropertySlotByIndex):
+        * bridge/runtime_method.cpp:
+        (JSC::RuntimeMethod::getOwnPropertySlot):
+        (JSC::RuntimeMethod::getOwnPropertyDescriptor):
+        * bridge/runtime_object.cpp:
+        (JSC::Bindings::RuntimeObject::getOwnPropertySlot):
+        (JSC::Bindings::RuntimeObject::getOwnPropertyDescriptor):
+            - Pass attributes to PropertySlot::set* methods.
+
 2013-08-18  Ryosuke Niwa  <rniwa@webkit.org>
 
         <https://webkit.org/b/119917> Pasting multiple lines into a textarea can introduce extra new lines
diff --git a/Source/WebCore/bindings/js/JSCSSStyleDeclarationCustom.cpp b/Source/WebCore/bindings/js/JSCSSStyleDeclarationCustom.cpp
index 5137b1d..725b70f 100644
--- a/Source/WebCore/bindings/js/JSCSSStyleDeclarationCustom.cpp
+++ b/Source/WebCore/bindings/js/JSCSSStyleDeclarationCustom.cpp
@@ -330,9 +330,9 @@
         return false;
 
     if (propertyInfo.hadPixelOrPosPrefix)
-        slot.setCustomIndex(this, static_cast<unsigned>(propertyInfo.propertyID), cssPropertyGetterPixelOrPosPrefixCallback);
+        slot.setCustomIndex(this, ReadOnly | DontDelete | DontEnum, static_cast<unsigned>(propertyInfo.propertyID), cssPropertyGetterPixelOrPosPrefixCallback);
     else
-        slot.setCustomIndex(this, static_cast<unsigned>(propertyInfo.propertyID), cssPropertyGetterCallback);
+        slot.setCustomIndex(this, ReadOnly | DontDelete | DontEnum, static_cast<unsigned>(propertyInfo.propertyID), cssPropertyGetterCallback);
     return true;
 }
 
diff --git a/Source/WebCore/bindings/js/JSDOMWindowCustom.cpp b/Source/WebCore/bindings/js/JSDOMWindowCustom.cpp
index d889b61..a10f289 100644
--- a/Source/WebCore/bindings/js/JSDOMWindowCustom.cpp
+++ b/Source/WebCore/bindings/js/JSDOMWindowCustom.cpp
@@ -126,12 +126,12 @@
         // It ignores any custom properties that might be set on the DOMWindow (including a custom prototype).
         entry = s_info.propHashTable(exec)->entry(exec, propertyName);
         if (entry && !(entry->attributes() & JSC::Function) && entry->propertyGetter() == jsDOMWindowClosed) {
-            slot.setCustom(thisObject, entry->propertyGetter());
+            slot.setCustom(thisObject, ReadOnly | DontDelete | DontEnum, entry->propertyGetter());
             return true;
         }
         entry = JSDOMWindowPrototype::info()->propHashTable(exec)->entry(exec, propertyName);
         if (entry && (entry->attributes() & JSC::Function) && entry->function() == jsDOMWindowPrototypeFunctionClose) {
-            slot.setCustom(thisObject, nonCachingStaticFunctionGetter<jsDOMWindowPrototypeFunctionClose, 0>);
+            slot.setCustom(thisObject, ReadOnly | DontDelete | DontEnum, nonCachingStaticFunctionGetter<jsDOMWindowPrototypeFunctionClose, 0>);
             return true;
         }
 
@@ -161,22 +161,22 @@
         if (entry->attributes() & JSC::Function) {
             if (entry->function() == jsDOMWindowPrototypeFunctionBlur) {
                 if (!allowsAccess) {
-                    slot.setCustom(thisObject, nonCachingStaticFunctionGetter<jsDOMWindowPrototypeFunctionBlur, 0>);
+                    slot.setCustom(thisObject, entry->attributes(), nonCachingStaticFunctionGetter<jsDOMWindowPrototypeFunctionBlur, 0>);
                     return true;
                 }
             } else if (entry->function() == jsDOMWindowPrototypeFunctionClose) {
                 if (!allowsAccess) {
-                    slot.setCustom(thisObject, nonCachingStaticFunctionGetter<jsDOMWindowPrototypeFunctionClose, 0>);
+                    slot.setCustom(thisObject, entry->attributes(), nonCachingStaticFunctionGetter<jsDOMWindowPrototypeFunctionClose, 0>);
                     return true;
                 }
             } else if (entry->function() == jsDOMWindowPrototypeFunctionFocus) {
                 if (!allowsAccess) {
-                    slot.setCustom(thisObject, nonCachingStaticFunctionGetter<jsDOMWindowPrototypeFunctionFocus, 0>);
+                    slot.setCustom(thisObject, entry->attributes(), nonCachingStaticFunctionGetter<jsDOMWindowPrototypeFunctionFocus, 0>);
                     return true;
                 }
             } else if (entry->function() == jsDOMWindowPrototypeFunctionPostMessage) {
                 if (!allowsAccess) {
-                    slot.setCustom(thisObject, nonCachingStaticFunctionGetter<jsDOMWindowPrototypeFunctionPostMessage, 2>);
+                    slot.setCustom(thisObject, entry->attributes(), nonCachingStaticFunctionGetter<jsDOMWindowPrototypeFunctionPostMessage, 2>);
                     return true;
                 }
             } else if (entry->function() == jsDOMWindowPrototypeFunctionShowModalDialog) {
@@ -190,7 +190,7 @@
         // Allow access to toString() cross-domain, but always Object.prototype.toString.
         if (propertyName == exec->propertyNames().toString) {
             if (!allowsAccess) {
-                slot.setCustom(thisObject, objectToStringFunctionGetter);
+                slot.setCustom(thisObject, ReadOnly | DontDelete | DontEnum, objectToStringFunctionGetter);
                 return true;
             }
         }
@@ -198,7 +198,7 @@
 
     entry = JSDOMWindow::info()->propHashTable(exec)->entry(exec, propertyName);
     if (entry) {
-        slot.setCustom(thisObject, entry->propertyGetter());
+        slot.setCustom(thisObject, entry->attributes(), entry->propertyGetter());
         return true;
     }
 
@@ -208,7 +208,7 @@
     // are in Moz but not IE. Since we have some of these, we have to do
     // it the Moz way.
     if (thisObject->impl()->frame()->tree()->scopedChild(propertyNameToAtomicString(propertyName))) {
-        slot.setCustom(thisObject, childFrameGetter);
+        slot.setCustom(thisObject, ReadOnly | DontDelete | DontEnum, childFrameGetter);
         return true;
     }
 
@@ -232,7 +232,7 @@
     unsigned i = propertyName.asIndex();
     if (i < thisObject->impl()->frame()->tree()->scopedChildCount()) {
         ASSERT(i != PropertyName::NotAnIndex);
-        slot.setCustomIndex(thisObject, i, indexGetter);
+        slot.setCustomIndex(thisObject, ReadOnly | DontDelete | DontEnum, i, indexGetter);
         return true;
     }
 
@@ -247,7 +247,7 @@
     if (document->isHTMLDocument()) {
         AtomicStringImpl* atomicPropertyName = findAtomicString(propertyName);
         if (atomicPropertyName && toHTMLDocument(document)->hasWindowNamedItem(atomicPropertyName)) {
-            slot.setCustom(thisObject, namedItemGetter);
+            slot.setCustom(thisObject, ReadOnly | DontDelete | DontEnum, namedItemGetter);
             return true;
         }
     }
@@ -285,7 +285,7 @@
     // are in Moz but not IE. Since we have some of these, we have to do
     // it the Moz way.
     if (thisObject->impl()->frame()->tree()->scopedChild(propertyNameToAtomicString(propertyName))) {
-        slot.setCustom(thisObject, childFrameGetter);
+        slot.setCustom(thisObject, ReadOnly | DontDelete | DontEnum, childFrameGetter);
         return true;
     }
     
@@ -308,7 +308,7 @@
     // allow window[1] or parent[1] etc. (#56983)
     if (index < thisObject->impl()->frame()->tree()->scopedChildCount()) {
         ASSERT(index != PropertyName::NotAnIndex);
-        slot.setCustomIndex(thisObject, index, indexGetter);
+        slot.setCustomIndex(thisObject, ReadOnly | DontDelete | DontEnum, index, indexGetter);
         return true;
     }
 
@@ -323,7 +323,7 @@
     if (document->isHTMLDocument()) {
         AtomicStringImpl* atomicPropertyName = findAtomicString(propertyName);
         if (atomicPropertyName && toHTMLDocument(document)->hasWindowNamedItem(atomicPropertyName)) {
-            slot.setCustom(thisObject, namedItemGetter);
+            slot.setCustom(thisObject, ReadOnly | DontDelete | DontEnum, namedItemGetter);
             return true;
         }
     }
@@ -352,7 +352,7 @@
         entry = JSDOMWindowPrototype::info()->propHashTable(exec)->entry(exec, propertyName);
         if (entry && (entry->attributes() & JSC::Function) && entry->function() == jsDOMWindowPrototypeFunctionClose) {
             PropertySlot slot(thisObject);
-            slot.setCustom(thisObject, nonCachingStaticFunctionGetter<jsDOMWindowPrototypeFunctionClose, 0>);
+            slot.setCustom(thisObject, ReadOnly | DontDelete | DontEnum, nonCachingStaticFunctionGetter<jsDOMWindowPrototypeFunctionClose, 0>);
             descriptor.setDescriptor(slot.getValue(exec, propertyName), ReadOnly | DontDelete | DontEnum);
             return true;
         }
@@ -363,7 +363,7 @@
     entry = JSDOMWindow::info()->propHashTable(exec)->entry(exec, propertyName);
     if (entry) {
         PropertySlot slot(thisObject);
-        slot.setCustom(thisObject, entry->propertyGetter());
+        slot.setCustom(thisObject, entry->attributes(), entry->propertyGetter());
         descriptor.setDescriptor(slot.getValue(exec, propertyName), entry->attributes());
         return true;
     }
@@ -375,7 +375,7 @@
     // it the Moz way.
     if (thisObject->impl()->frame()->tree()->scopedChild(propertyNameToAtomicString(propertyName))) {
         PropertySlot slot(thisObject);
-        slot.setCustom(thisObject, childFrameGetter);
+        slot.setCustom(thisObject, ReadOnly | DontDelete | DontEnum, childFrameGetter);
         descriptor.setDescriptor(slot.getValue(exec, propertyName), ReadOnly | DontDelete | DontEnum);
         return true;
     }
@@ -384,7 +384,7 @@
     if (i < thisObject->impl()->frame()->tree()->scopedChildCount()) {
         ASSERT(i != PropertyName::NotAnIndex);
         PropertySlot slot(thisObject);
-        slot.setCustomIndex(thisObject, i, indexGetter);
+        slot.setCustomIndex(thisObject, ReadOnly | DontDelete | DontEnum, i, indexGetter);
         descriptor.setDescriptor(slot.getValue(exec, propertyName), ReadOnly | DontDelete | DontEnum);
         return true;
     }
@@ -395,7 +395,7 @@
         AtomicStringImpl* atomicPropertyName = findAtomicString(propertyName);
         if (atomicPropertyName && toHTMLDocument(document)->hasWindowNamedItem(atomicPropertyName)) {
             PropertySlot slot(thisObject);
-            slot.setCustom(thisObject, namedItemGetter);
+            slot.setCustom(thisObject, ReadOnly | DontDelete | DontEnum, namedItemGetter);
             descriptor.setDescriptor(slot.getValue(exec, propertyName), ReadOnly | DontDelete | DontEnum);
             return true;
         }
diff --git a/Source/WebCore/bindings/js/JSHistoryCustom.cpp b/Source/WebCore/bindings/js/JSHistoryCustom.cpp
index 7034275..9f92612 100644
--- a/Source/WebCore/bindings/js/JSHistoryCustom.cpp
+++ b/Source/WebCore/bindings/js/JSHistoryCustom.cpp
@@ -70,20 +70,20 @@
         // Allow access to back(), forward() and go() from any frame.
         if (entry->attributes() & JSC::Function) {
             if (entry->function() == jsHistoryPrototypeFunctionBack) {
-                slot.setCustom(this, nonCachingStaticBackFunctionGetter);
+                slot.setCustom(this, entry->attributes(), nonCachingStaticBackFunctionGetter);
                 return true;
             } else if (entry->function() == jsHistoryPrototypeFunctionForward) {
-                slot.setCustom(this, nonCachingStaticForwardFunctionGetter);
+                slot.setCustom(this, entry->attributes(), nonCachingStaticForwardFunctionGetter);
                 return true;
             } else if (entry->function() == jsHistoryPrototypeFunctionGo) {
-                slot.setCustom(this, nonCachingStaticGoFunctionGetter);
+                slot.setCustom(this, entry->attributes(), nonCachingStaticGoFunctionGetter);
                 return true;
             }
         }
     } else {
         // Allow access to toString() cross-domain, but always Object.toString.
         if (propertyName == exec->propertyNames().toString) {
-            slot.setCustom(this, objectToStringFunctionGetter);
+            slot.setCustom(this, ReadOnly | DontDelete | DontEnum, objectToStringFunctionGetter);
             return true;
         }
     }
@@ -111,15 +111,15 @@
         // Allow access to back(), forward() and go() from any frame.
         if (entry->attributes() & JSC::Function) {
             if (entry->function() == jsHistoryPrototypeFunctionBack) {
-                slot.setCustom(this, nonCachingStaticBackFunctionGetter);
+                slot.setCustom(this, entry->attributes(), nonCachingStaticBackFunctionGetter);
                 descriptor.setDescriptor(slot.getValue(exec, propertyName), entry->attributes());
                 return true;
             } else if (entry->function() == jsHistoryPrototypeFunctionForward) {
-                slot.setCustom(this, nonCachingStaticForwardFunctionGetter);
+                slot.setCustom(this, entry->attributes(), nonCachingStaticForwardFunctionGetter);
                 descriptor.setDescriptor(slot.getValue(exec, propertyName), entry->attributes());
                 return true;
             } else if (entry->function() == jsHistoryPrototypeFunctionGo) {
-                slot.setCustom(this, nonCachingStaticGoFunctionGetter);
+                slot.setCustom(this, entry->attributes(), nonCachingStaticGoFunctionGetter);
                 descriptor.setDescriptor(slot.getValue(exec, propertyName), entry->attributes());
                 return true;
             }
@@ -128,7 +128,7 @@
         // Allow access to toString() cross-domain, but always Object.toString.
         if (propertyName == exec->propertyNames().toString) {
             PropertySlot slot(this);
-            slot.setCustom(this, objectToStringFunctionGetter);
+            slot.setCustom(this, ReadOnly | DontDelete | DontEnum, objectToStringFunctionGetter);
             descriptor.setDescriptor(slot.getValue(exec, propertyName), entry->attributes());
             return true;
         }
diff --git a/Source/WebCore/bindings/js/JSLocationCustom.cpp b/Source/WebCore/bindings/js/JSLocationCustom.cpp
index 9f368dc..374d7e0 100644
--- a/Source/WebCore/bindings/js/JSLocationCustom.cpp
+++ b/Source/WebCore/bindings/js/JSLocationCustom.cpp
@@ -66,13 +66,13 @@
     const HashEntry* entry = JSLocationPrototype::info()->propHashTable(exec)->entry(exec, propertyName);
     if (entry && (entry->attributes() & JSC::Function)) {
         if (entry->function() == jsLocationPrototypeFunctionReplace) {
-            slot.setCustom(this, nonCachingStaticReplaceFunctionGetter);
+            slot.setCustom(this, entry->attributes(), nonCachingStaticReplaceFunctionGetter);
             return true;
         } else if (entry->function() == jsLocationPrototypeFunctionReload) {
-            slot.setCustom(this, nonCachingStaticReloadFunctionGetter);
+            slot.setCustom(this, entry->attributes(), nonCachingStaticReloadFunctionGetter);
             return true;
         } else if (entry->function() == jsLocationPrototypeFunctionAssign) {
-            slot.setCustom(this, nonCachingStaticAssignFunctionGetter);
+            slot.setCustom(this, entry->attributes(), nonCachingStaticAssignFunctionGetter);
             return true;
         }
     }
@@ -103,15 +103,15 @@
     PropertySlot slot(this);
     if (entry && (entry->attributes() & JSC::Function)) {
         if (entry->function() == jsLocationPrototypeFunctionReplace) {
-            slot.setCustom(this, nonCachingStaticReplaceFunctionGetter);
+            slot.setCustom(this, entry->attributes(), nonCachingStaticReplaceFunctionGetter);
             descriptor.setDescriptor(slot.getValue(exec, propertyName), entry->attributes());
             return true;
         } else if (entry->function() == jsLocationPrototypeFunctionReload) {
-            slot.setCustom(this, nonCachingStaticReloadFunctionGetter);
+            slot.setCustom(this, entry->attributes(), nonCachingStaticReloadFunctionGetter);
             descriptor.setDescriptor(slot.getValue(exec, propertyName), entry->attributes());
             return true;
         } else if (entry->function() == jsLocationPrototypeFunctionAssign) {
-            slot.setCustom(this, nonCachingStaticAssignFunctionGetter);
+            slot.setCustom(this, entry->attributes(), nonCachingStaticAssignFunctionGetter);
             descriptor.setDescriptor(slot.getValue(exec, propertyName), entry->attributes());
             return true;
         }
diff --git a/Source/WebCore/bindings/js/JSPluginElementFunctions.cpp b/Source/WebCore/bindings/js/JSPluginElementFunctions.cpp
index 00b19b8..fd01efd 100644
--- a/Source/WebCore/bindings/js/JSPluginElementFunctions.cpp
+++ b/Source/WebCore/bindings/js/JSPluginElementFunctions.cpp
@@ -118,7 +118,7 @@
 
     if (!scriptObject->hasProperty(exec, propertyName))
         return false;
-    slot.setCustom(element, runtimeObjectPropertyGetter);
+    slot.setCustom(element, DontDelete | DontEnum, runtimeObjectPropertyGetter);
     return true;
 }
 
@@ -130,7 +130,7 @@
     if (!scriptObject->hasProperty(exec, propertyName))
         return false;
     PropertySlot slot(element);
-    slot.setCustom(element, runtimeObjectPropertyGetter);
+    slot.setCustom(element, DontDelete | DontEnum, runtimeObjectPropertyGetter);
     // While we don't know what the plugin allows, we do know that we prevent
     // enumeration or deletion of properties, so we mark plugin properties
     // as DontEnum | DontDelete
diff --git a/Source/WebCore/bindings/scripts/CodeGeneratorJS.pm b/Source/WebCore/bindings/scripts/CodeGeneratorJS.pm
index ecbfb8e..94b114e 100644
--- a/Source/WebCore/bindings/scripts/CodeGeneratorJS.pm
+++ b/Source/WebCore/bindings/scripts/CodeGeneratorJS.pm
@@ -361,7 +361,7 @@
         if ($requiresManualLookup) {
             push(@getOwnPropertySlotImpl, "    const ${namespaceMaybe}HashEntry* entry = getStaticValueSlotEntryWithoutCaching<$className>(exec, propertyName);\n");
             push(@getOwnPropertySlotImpl, "    if (entry) {\n");
-            push(@getOwnPropertySlotImpl, "        slot.setCustom(thisObject, entry->propertyGetter());\n");
+            push(@getOwnPropertySlotImpl, "        slot.setCustom(thisObject, entry->attributes(), entry->propertyGetter());\n");
             push(@getOwnPropertySlotImpl, "        return true;\n");
             push(@getOwnPropertySlotImpl, "    }\n");
         }
@@ -381,10 +381,16 @@
         } else {
             push(@getOwnPropertySlotImpl, "    if (index != PropertyName::NotAnIndex && index < static_cast<$interfaceName*>(thisObject->impl())->length()) {\n");
         }
-        if ($hasNumericIndexedGetter) {
-            push(@getOwnPropertySlotImpl, "        slot.setValue(thisObject, thisObject->getByIndex(exec, index));\n");
+        # Assume that if there's a setter, the index will be writable
+        if ($interface->extendedAttributes->{"CustomIndexedSetter"}) {
+            push(@getOwnPropertySlotImpl, "        unsigned attributes = ${namespaceMaybe}DontDelete;\n");
         } else {
-            push(@getOwnPropertySlotImpl, "        slot.setCustomIndex(thisObject, index, indexGetter);\n");
+            push(@getOwnPropertySlotImpl, "        unsigned attributes = ${namespaceMaybe}DontDelete | ${namespaceMaybe}ReadOnly;\n");
+        }
+        if ($hasNumericIndexedGetter) {
+            push(@getOwnPropertySlotImpl, "        slot.setValue(thisObject, attributes, thisObject->getByIndex(exec, index));\n");
+        } else {
+            push(@getOwnPropertySlotImpl, "        slot.setCustomIndex(thisObject, attributes, index, indexGetter);\n");
         }
         push(@getOwnPropertySlotImpl, "        return true;\n");
         push(@getOwnPropertySlotImpl, "    }\n");
@@ -392,7 +398,7 @@
 
     if ($namedGetterFunction || $interface->extendedAttributes->{"CustomNamedGetter"}) {
         push(@getOwnPropertySlotImpl, "    if (canGetItemsForName(exec, static_cast<$interfaceName*>(thisObject->impl()), propertyName)) {\n");
-        push(@getOwnPropertySlotImpl, "        slot.setCustom(thisObject, thisObject->nameGetter);\n");
+        push(@getOwnPropertySlotImpl, "        slot.setCustom(thisObject, ReadOnly | DontDelete | DontEnum, thisObject->nameGetter);\n");
         push(@getOwnPropertySlotImpl, "        return true;\n");
         push(@getOwnPropertySlotImpl, "    }\n");
         if ($inlined) {
@@ -458,7 +464,7 @@
             push(@getOwnPropertyDescriptorImpl, "    const ${namespaceMaybe}HashEntry* entry = ${className}Table.entry(exec, propertyName);\n");
             push(@getOwnPropertyDescriptorImpl, "    if (entry) {\n");
             push(@getOwnPropertyDescriptorImpl, "        PropertySlot slot(thisObject);\n");
-            push(@getOwnPropertyDescriptorImpl, "        slot.setCustom(thisObject, entry->propertyGetter());\n");
+            push(@getOwnPropertyDescriptorImpl, "        slot.setCustom(thisObject, entry->attributes(), entry->propertyGetter());\n");
             push(@getOwnPropertyDescriptorImpl, "        descriptor.setDescriptor(slot.getValue(exec, propertyName), entry->attributes());\n");
             push(@getOwnPropertyDescriptorImpl, "        return true;\n");
             push(@getOwnPropertyDescriptorImpl, "    }\n");
@@ -472,22 +478,18 @@
     if ($indexedGetterFunction) {
         push(@getOwnPropertyDescriptorImpl, "    unsigned index = propertyName.asIndex();\n");
         push(@getOwnPropertyDescriptorImpl, "    if (index != PropertyName::NotAnIndex && index < static_cast<$interfaceName*>(thisObject->impl())->length()) {\n");
+        # Assume that if there's a setter, the index will be writable
+        if ($interface->extendedAttributes->{"CustomIndexedSetter"}) {
+            push(@getOwnPropertyDescriptorImpl, "        unsigned attributes = ${namespaceMaybe}DontDelete;\n");
+        } else {
+            push(@getOwnPropertyDescriptorImpl, "        unsigned attributes = ${namespaceMaybe}DontDelete | ${namespaceMaybe}ReadOnly;\n");
+        }
         if ($hasNumericIndexedGetter) {
-            # Assume that if there's a setter, the index will be writable
-            if ($interface->extendedAttributes->{"CustomIndexedSetter"}) {
-                push(@getOwnPropertyDescriptorImpl, "        descriptor.setDescriptor(thisObject->getByIndex(exec, index), ${namespaceMaybe}DontDelete);\n");
-            } else {
-                push(@getOwnPropertyDescriptorImpl, "        descriptor.setDescriptor(thisObject->getByIndex(exec, index), ${namespaceMaybe}DontDelete | ${namespaceMaybe}ReadOnly);\n");
-            }
+            push(@getOwnPropertyDescriptorImpl, "        descriptor.setDescriptor(thisObject->getByIndex(exec, index), attributes);\n");
         } else {
             push(@getOwnPropertyDescriptorImpl, "        ${namespaceMaybe}PropertySlot slot(thisObject);\n");
-            push(@getOwnPropertyDescriptorImpl, "        slot.setCustomIndex(thisObject, index, indexGetter);\n");
-            # Assume that if there's a setter, the index will be writable
-            if ($interface->extendedAttributes->{"CustomIndexedSetter"}) {
-                push(@getOwnPropertyDescriptorImpl, "        descriptor.setDescriptor(slot.getValue(exec, propertyName), ${namespaceMaybe}DontDelete);\n");
-            } else {
-                push(@getOwnPropertyDescriptorImpl, "        descriptor.setDescriptor(slot.getValue(exec, propertyName), ${namespaceMaybe}DontDelete | ${namespaceMaybe}ReadOnly);\n");
-            }
+            push(@getOwnPropertyDescriptorImpl, "        slot.setCustomIndex(thisObject, attributes, index, indexGetter);\n");
+            push(@getOwnPropertyDescriptorImpl, "        descriptor.setDescriptor(slot.getValue(exec, propertyName), attributes);\n");
         }
         push(@getOwnPropertyDescriptorImpl, "        return true;\n");
         push(@getOwnPropertyDescriptorImpl, "    }\n");
@@ -496,7 +498,7 @@
     if ($namedGetterFunction || $interface->extendedAttributes->{"CustomNamedGetter"}) {
         push(@getOwnPropertyDescriptorImpl, "    if (canGetItemsForName(exec, static_cast<$interfaceName*>(thisObject->impl()), propertyName)) {\n");
         push(@getOwnPropertyDescriptorImpl, "        ${namespaceMaybe}PropertySlot slot(thisObject);\n");
-        push(@getOwnPropertyDescriptorImpl, "        slot.setCustom(thisObject, nameGetter);\n");
+        push(@getOwnPropertyDescriptorImpl, "        slot.setCustom(thisObject, ReadOnly | DontDelete | DontEnum, nameGetter);\n");
         push(@getOwnPropertyDescriptorImpl, "        descriptor.setDescriptor(slot.getValue(exec, propertyName), ReadOnly | DontDelete | DontEnum);\n");
         push(@getOwnPropertyDescriptorImpl, "        return true;\n");
         push(@getOwnPropertyDescriptorImpl, "    }\n");
@@ -1934,10 +1936,16 @@
                 } else {
                     push(@implContent, "    if (index < static_cast<$interfaceName*>(thisObject->impl())->length()) {\n");
                 }
-                if ($hasNumericIndexedGetter) {
-                    push(@implContent, "        slot.setValue(thisObject, thisObject->getByIndex(exec, index));\n");
+                # Assume that if there's a setter, the index will be writable
+                if ($interface->extendedAttributes->{"CustomIndexedSetter"}) {
+                    push(@implContent, "        unsigned attributes = DontDelete;\n");
                 } else {
-                    push(@implContent, "        slot.setCustomIndex(thisObject, index, thisObject->indexGetter);\n");
+                    push(@implContent, "        unsigned attributes = DontDelete | ReadOnly;\n");
+                }
+                if ($hasNumericIndexedGetter) {
+                    push(@implContent, "        slot.setValue(thisObject, attributes, thisObject->getByIndex(exec, index));\n");
+                } else {
+                    push(@implContent, "        slot.setCustomIndex(thisObject, attributes, index, thisObject->indexGetter);\n");
                 }
                 push(@implContent, "        return true;\n");
                 push(@implContent, "    }\n");
@@ -1946,7 +1954,7 @@
             if ($namedGetterFunction || $interface->extendedAttributes->{"CustomNamedGetter"}) {
                 &$propertyNameGeneration();
                 push(@implContent, "    if (canGetItemsForName(exec, static_cast<$interfaceName*>(thisObject->impl()), propertyName)) {\n");
-                push(@implContent, "        slot.setCustom(thisObject, thisObject->nameGetter);\n");
+                push(@implContent, "        slot.setCustom(thisObject, ReadOnly | DontDelete | DontEnum, thisObject->nameGetter);\n");
                 push(@implContent, "        return true;\n");
                 push(@implContent, "    }\n");
                 $implIncludes{"wtf/text/AtomicString.h"} = 1;
diff --git a/Source/WebCore/bindings/scripts/test/JS/JSTestCustomNamedGetter.cpp b/Source/WebCore/bindings/scripts/test/JS/JSTestCustomNamedGetter.cpp
index 3e05921..5cc1275 100644
--- a/Source/WebCore/bindings/scripts/test/JS/JSTestCustomNamedGetter.cpp
+++ b/Source/WebCore/bindings/scripts/test/JS/JSTestCustomNamedGetter.cpp
@@ -137,7 +137,7 @@
     JSTestCustomNamedGetter* thisObject = jsCast<JSTestCustomNamedGetter*>(object);
     ASSERT_GC_OBJECT_INHERITS(thisObject, info());
     if (canGetItemsForName(exec, static_cast<TestCustomNamedGetter*>(thisObject->impl()), propertyName)) {
-        slot.setCustom(thisObject, thisObject->nameGetter);
+        slot.setCustom(thisObject, ReadOnly | DontDelete | DontEnum, thisObject->nameGetter);
         return true;
     }
     return getStaticValueSlot<JSTestCustomNamedGetter, Base>(exec, &JSTestCustomNamedGetterTable, thisObject, propertyName, slot);
@@ -149,7 +149,7 @@
     ASSERT_GC_OBJECT_INHERITS(thisObject, info());
     if (canGetItemsForName(exec, static_cast<TestCustomNamedGetter*>(thisObject->impl()), propertyName)) {
         PropertySlot slot(thisObject);
-        slot.setCustom(thisObject, nameGetter);
+        slot.setCustom(thisObject, ReadOnly | DontDelete | DontEnum, nameGetter);
         descriptor.setDescriptor(slot.getValue(exec, propertyName), ReadOnly | DontDelete | DontEnum);
         return true;
     }
@@ -162,7 +162,7 @@
     ASSERT_GC_OBJECT_INHERITS(thisObject, info());
     PropertyName propertyName = Identifier::from(exec, index);
     if (canGetItemsForName(exec, static_cast<TestCustomNamedGetter*>(thisObject->impl()), propertyName)) {
-        slot.setCustom(thisObject, thisObject->nameGetter);
+        slot.setCustom(thisObject, ReadOnly | DontDelete | DontEnum, thisObject->nameGetter);
         return true;
     }
     return Base::getOwnPropertySlotByIndex(thisObject, exec, index, slot);
diff --git a/Source/WebCore/bindings/scripts/test/JS/JSTestEventTarget.cpp b/Source/WebCore/bindings/scripts/test/JS/JSTestEventTarget.cpp
index a78d1e5..99d59d4 100644
--- a/Source/WebCore/bindings/scripts/test/JS/JSTestEventTarget.cpp
+++ b/Source/WebCore/bindings/scripts/test/JS/JSTestEventTarget.cpp
@@ -147,16 +147,17 @@
     ASSERT_GC_OBJECT_INHERITS(thisObject, info());
     const HashEntry* entry = getStaticValueSlotEntryWithoutCaching<JSTestEventTarget>(exec, propertyName);
     if (entry) {
-        slot.setCustom(thisObject, entry->propertyGetter());
+        slot.setCustom(thisObject, entry->attributes(), entry->propertyGetter());
         return true;
     }
     unsigned index = propertyName.asIndex();
     if (index != PropertyName::NotAnIndex && index < static_cast<TestEventTarget*>(thisObject->impl())->length()) {
-        slot.setCustomIndex(thisObject, index, indexGetter);
+        unsigned attributes = DontDelete | ReadOnly;
+        slot.setCustomIndex(thisObject, attributes, index, indexGetter);
         return true;
     }
     if (canGetItemsForName(exec, static_cast<TestEventTarget*>(thisObject->impl()), propertyName)) {
-        slot.setCustom(thisObject, thisObject->nameGetter);
+        slot.setCustom(thisObject, ReadOnly | DontDelete | DontEnum, thisObject->nameGetter);
         return true;
     }
     return getStaticValueSlot<JSTestEventTarget, Base>(exec, &JSTestEventTargetTable, thisObject, propertyName, slot);
@@ -169,20 +170,21 @@
     const HashEntry* entry = JSTestEventTargetTable.entry(exec, propertyName);
     if (entry) {
         PropertySlot slot(thisObject);
-        slot.setCustom(thisObject, entry->propertyGetter());
+        slot.setCustom(thisObject, entry->attributes(), entry->propertyGetter());
         descriptor.setDescriptor(slot.getValue(exec, propertyName), entry->attributes());
         return true;
     }
     unsigned index = propertyName.asIndex();
     if (index != PropertyName::NotAnIndex && index < static_cast<TestEventTarget*>(thisObject->impl())->length()) {
+        unsigned attributes = DontDelete | ReadOnly;
         PropertySlot slot(thisObject);
-        slot.setCustomIndex(thisObject, index, indexGetter);
-        descriptor.setDescriptor(slot.getValue(exec, propertyName), DontDelete | ReadOnly);
+        slot.setCustomIndex(thisObject, attributes, index, indexGetter);
+        descriptor.setDescriptor(slot.getValue(exec, propertyName), attributes);
         return true;
     }
     if (canGetItemsForName(exec, static_cast<TestEventTarget*>(thisObject->impl()), propertyName)) {
         PropertySlot slot(thisObject);
-        slot.setCustom(thisObject, nameGetter);
+        slot.setCustom(thisObject, ReadOnly | DontDelete | DontEnum, nameGetter);
         descriptor.setDescriptor(slot.getValue(exec, propertyName), ReadOnly | DontDelete | DontEnum);
         return true;
     }
@@ -194,12 +196,13 @@
     JSTestEventTarget* thisObject = jsCast<JSTestEventTarget*>(object);
     ASSERT_GC_OBJECT_INHERITS(thisObject, info());
     if (index < static_cast<TestEventTarget*>(thisObject->impl())->length()) {
-        slot.setCustomIndex(thisObject, index, thisObject->indexGetter);
+        unsigned attributes = DontDelete | ReadOnly;
+        slot.setCustomIndex(thisObject, attributes, index, thisObject->indexGetter);
         return true;
     }
     PropertyName propertyName = Identifier::from(exec, index);
     if (canGetItemsForName(exec, static_cast<TestEventTarget*>(thisObject->impl()), propertyName)) {
-        slot.setCustom(thisObject, thisObject->nameGetter);
+        slot.setCustom(thisObject, ReadOnly | DontDelete | DontEnum, thisObject->nameGetter);
         return true;
     }
     return Base::getOwnPropertySlotByIndex(thisObject, exec, index, slot);
diff --git a/Source/WebCore/bridge/runtime_array.cpp b/Source/WebCore/bridge/runtime_array.cpp
index 7b55cbf..baff7f7 100644
--- a/Source/WebCore/bridge/runtime_array.cpp
+++ b/Source/WebCore/bridge/runtime_array.cpp
@@ -89,14 +89,14 @@
 {
     RuntimeArray* thisObject = jsCast<RuntimeArray*>(object);
     if (propertyName == exec->propertyNames().length) {
-        slot.setCacheableCustom(thisObject, thisObject->lengthGetter);
+        slot.setCacheableCustom(thisObject, DontDelete | ReadOnly | DontEnum, thisObject->lengthGetter);
         return true;
     }
     
     unsigned index = propertyName.asIndex();
     if (index < thisObject->getLength()) {
         ASSERT(index != PropertyName::NotAnIndex);
-        slot.setCustomIndex(thisObject, index, thisObject->indexGetter);
+        slot.setCustomIndex(thisObject, DontDelete | DontEnum, index, thisObject->indexGetter);
         return true;
     }
     
@@ -108,7 +108,7 @@
     RuntimeArray* thisObject = jsCast<RuntimeArray*>(object);
     if (propertyName == exec->propertyNames().length) {
         PropertySlot slot(thisObject);
-        slot.setCustom(thisObject, lengthGetter);
+        slot.setCustom(thisObject, DontDelete | ReadOnly | DontEnum, lengthGetter);
         descriptor.setDescriptor(slot.getValue(exec, propertyName), ReadOnly | DontDelete | DontEnum);
         return true;
     }
@@ -117,7 +117,7 @@
     if (index < thisObject->getLength()) {
         ASSERT(index != PropertyName::NotAnIndex);
         PropertySlot slot(thisObject);
-        slot.setCustomIndex(thisObject, index, indexGetter);
+        slot.setCustomIndex(thisObject, DontDelete | DontEnum, index, indexGetter);
         descriptor.setDescriptor(slot.getValue(exec, propertyName), DontDelete | DontEnum);
         return true;
     }
@@ -129,7 +129,7 @@
 {
     RuntimeArray* thisObject = jsCast<RuntimeArray*>(object);
     if (index < thisObject->getLength()) {
-        slot.setCustomIndex(thisObject, index, thisObject->indexGetter);
+        slot.setCustomIndex(thisObject, DontDelete | DontEnum, index, thisObject->indexGetter);
         return true;
     }
     
diff --git a/Source/WebCore/bridge/runtime_method.cpp b/Source/WebCore/bridge/runtime_method.cpp
index 661e803..e1dce7a 100644
--- a/Source/WebCore/bridge/runtime_method.cpp
+++ b/Source/WebCore/bridge/runtime_method.cpp
@@ -65,7 +65,7 @@
 {
     RuntimeMethod* thisObject = jsCast<RuntimeMethod*>(object);
     if (propertyName == exec->propertyNames().length) {
-        slot.setCacheableCustom(thisObject, thisObject->lengthGetter);
+        slot.setCacheableCustom(thisObject, DontDelete | ReadOnly | DontEnum, thisObject->lengthGetter);
         return true;
     }
     
@@ -77,7 +77,7 @@
     RuntimeMethod* thisObject = jsCast<RuntimeMethod*>(object);
     if (propertyName == exec->propertyNames().length) {
         PropertySlot slot(thisObject);
-        slot.setCustom(thisObject, lengthGetter);
+        slot.setCustom(thisObject, DontDelete | ReadOnly | DontEnum, lengthGetter);
         descriptor.setDescriptor(slot.getValue(exec, propertyName), ReadOnly | DontDelete | DontEnum);
         return true;
     }
diff --git a/Source/WebCore/bridge/runtime_object.cpp b/Source/WebCore/bridge/runtime_object.cpp
index a26d8d6..5513ae5 100644
--- a/Source/WebCore/bridge/runtime_object.cpp
+++ b/Source/WebCore/bridge/runtime_object.cpp
@@ -134,14 +134,14 @@
         // See if the instance has a field with the specified name.
         Field *aField = aClass->fieldNamed(propertyName, instance.get());
         if (aField) {
-            slot.setCustom(thisObject, thisObject->fieldGetter);
+            slot.setCustom(thisObject, DontDelete, thisObject->fieldGetter);
             instance->end();
             return true;
         } else {
             // Now check if a method with specified name exists, if so return a function object for
             // that method.
             if (aClass->methodNamed(propertyName, instance.get())) {
-                slot.setCustom(thisObject, thisObject->methodGetter);
+                slot.setCustom(thisObject, DontDelete | ReadOnly, thisObject->methodGetter);
                 
                 instance->end();
                 return true;
@@ -150,7 +150,7 @@
 
         // Try a fallback object.
         if (!aClass->fallbackObject(exec, instance.get(), propertyName).isUndefined()) {
-            slot.setCustom(thisObject, thisObject->fallbackObjectGetter);
+            slot.setCustom(thisObject, DontDelete | ReadOnly | DontEnum, thisObject->fallbackObjectGetter);
             instance->end();
             return true;
         }
@@ -179,7 +179,7 @@
         Field *aField = aClass->fieldNamed(propertyName, instance.get());
         if (aField) {
             PropertySlot slot(thisObject);
-            slot.setCustom(thisObject, fieldGetter);
+            slot.setCustom(thisObject, DontDelete, fieldGetter);
             instance->end();
             descriptor.setDescriptor(slot.getValue(exec, propertyName), DontDelete);
             return true;
@@ -188,7 +188,7 @@
             // that method.
             if (aClass->methodNamed(propertyName, instance.get())) {
                 PropertySlot slot(thisObject);
-                slot.setCustom(thisObject, methodGetter);
+                slot.setCustom(thisObject, DontDelete | ReadOnly, methodGetter);
                 instance->end();
                 descriptor.setDescriptor(slot.getValue(exec, propertyName), DontDelete | ReadOnly);
                 return true;
@@ -198,7 +198,7 @@
         // Try a fallback object.
         if (!aClass->fallbackObject(exec, instance.get(), propertyName).isUndefined()) {
             PropertySlot slot(thisObject);
-            slot.setCustom(thisObject, fallbackObjectGetter);
+            slot.setCustom(thisObject, DontDelete | ReadOnly | DontEnum, fallbackObjectGetter);
             instance->end();
             descriptor.setDescriptor(slot.getValue(exec, propertyName), DontDelete | ReadOnly | DontEnum);
             return true;
diff --git a/Source/WebKit2/ChangeLog b/Source/WebKit2/ChangeLog
index cb40dae..c200ac6 100644
--- a/Source/WebKit2/ChangeLog
+++ b/Source/WebKit2/ChangeLog
@@ -1,3 +1,19 @@
+2013-08-18  Gavin Barraclough  <barraclough@apple.com>
+
+        https://bugs.webkit.org/show_bug.cgi?id=119972
+        Add attributes field to PropertySlot
+
+        Reviewed by Geoff Garen.
+
+        For all JSC types, this makes getOwnPropertyDescriptor redundant.
+        There will be a bit more hacking required in WebCore to remove GOPD whilst maintaining current behaviour.
+        (Current behaviour is in many ways broken, particularly in that GOPD & GOPS are inconsistent, but we should fix incrementally).
+
+        * WebProcess/Plugins/Netscape/JSNPObject.cpp:
+        (WebKit::JSNPObject::getOwnPropertySlot):
+        (WebKit::JSNPObject::getOwnPropertyDescriptor):
+            - Pass attributes to PropertySlot::set* methods.
+
 2013-08-16  Sam Weinig  <sam@webkit.org>
 
         <https://webkit.org/b/119911> Remove the unused OfflineStorageProcess
diff --git a/Source/WebKit2/WebProcess/Plugins/Netscape/JSNPObject.cpp b/Source/WebKit2/WebProcess/Plugins/Netscape/JSNPObject.cpp
index e8720df..7fe45f6 100644
--- a/Source/WebKit2/WebProcess/Plugins/Netscape/JSNPObject.cpp
+++ b/Source/WebKit2/WebProcess/Plugins/Netscape/JSNPObject.cpp
@@ -276,13 +276,13 @@
 
     // First, check if the NPObject has a property with this name.
     if (thisObject->m_npObject->_class->hasProperty && thisObject->m_npObject->_class->hasProperty(thisObject->m_npObject, npIdentifier)) {
-        slot.setCustom(thisObject, thisObject->propertyGetter);
+        slot.setCustom(thisObject, DontDelete, thisObject->propertyGetter);
         return true;
     }
 
     // Second, check if the NPObject has a method with this name.
     if (thisObject->m_npObject->_class->hasMethod && thisObject->m_npObject->_class->hasMethod(thisObject->m_npObject, npIdentifier)) {
-        slot.setCustom(thisObject, thisObject->methodGetter);
+        slot.setCustom(thisObject, DontDelete | ReadOnly, thisObject->methodGetter);
         return true;
     }
     
@@ -308,7 +308,7 @@
     // First, check if the NPObject has a property with this name.
     if (thisObject->m_npObject->_class->hasProperty && thisObject->m_npObject->_class->hasProperty(thisObject->m_npObject, npIdentifier)) {
         PropertySlot slot(thisObject);
-        slot.setCustom(thisObject, propertyGetter);
+        slot.setCustom(thisObject, DontDelete, propertyGetter);
         descriptor.setDescriptor(slot.getValue(exec, propertyName), DontDelete);
         return true;
     }
@@ -316,7 +316,7 @@
     // Second, check if the NPObject has a method with this name.
     if (thisObject->m_npObject->_class->hasMethod && thisObject->m_npObject->_class->hasMethod(thisObject->m_npObject, npIdentifier)) {
         PropertySlot slot(thisObject);
-        slot.setCustom(thisObject, methodGetter);
+        slot.setCustom(thisObject, DontDelete | ReadOnly, methodGetter);
         descriptor.setDescriptor(slot.getValue(exec, propertyName), DontDelete | ReadOnly);
         return true;
     }